Skip to content

Commit

Permalink
Insights and minor changes for v2.3
Browse files Browse the repository at this point in the history
Summary: Added insights edge and bumped version for v2.3

Test Plan:
Run tests
tox
python -m facebookads.test.integration
  • Loading branch information
Evan Chen committed Mar 25, 2015
1 parent c03fbcf commit 5679bbf
Show file tree
Hide file tree
Showing 6 changed files with 180 additions and 31 deletions.
4 changes: 2 additions & 2 deletions facebookads/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,9 +129,9 @@ class FacebookAdsApi(object):
this sdk.
"""

SDK_VERSION = '2.2.7'
SDK_VERSION = '2.3.0'

API_VERSION = 'v2.2'
API_VERSION = 'v2.3'

HTTP_METHOD_GET = 'GET'

Expand Down
166 changes: 162 additions & 4 deletions facebookads/objects.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,8 @@ def load_next_page(self):
if self._finished_iteration:
return False

self._params['summary'] = True
if 'summary' not in self._params:
self._params['summary'] = True

response = self._source_object.get_api_assured().call(
'GET',
Expand Down Expand Up @@ -804,6 +805,7 @@ class Field(object):
agency_client_declaration = 'agency_client_declaration'
amount_spent = 'amount_spent'
balance = 'balance'
business = 'business'
business_city = 'business_city'
business_country_code = 'business_country_code'
business_name = 'business_name'
Expand Down Expand Up @@ -941,6 +943,11 @@ def get_ad_images(self, fields=None, params=None):
"""Returns iterator over AdImage's associated with this account."""
return self.iterate_edge(AdImage, fields, params)

def get_insights(self, fields=None, params=None):
params = params or {}
params['summary'] = params.get('summary')
return self.iterate_edge(Insights, fields, params)

def get_broad_category_targeting(self, fields=None, params=None):
"""
Returns iterator over BroadCategoryTargeting's associated with this
Expand Down Expand Up @@ -1125,6 +1132,11 @@ def get_stats(self, fields=None, params=None):
"""Returns iterator over AdStat's associated with this campaign."""
return self.iterate_edge(AdStats, fields, params)

def get_insights(self, fields=None, params=None):
params = params or {}
params['summary'] = params.get('summary')
return self.iterate_edge(Insights, fields, params)


class AdSet(CanValidate, HasStatus, CanArchive, AbstractCrudObject):

Expand Down Expand Up @@ -1175,6 +1187,11 @@ def get_stats(self, fields=None, params=None):
"""Returns iterator over AdStat's associated with this set."""
return self.iterate_edge(AdStats, fields, params)

def get_insights(self, fields=None, params=None):
params = params or {}
params['summary'] = params.get('summary')
return self.iterate_edge(Insights, fields, params)


class AdGroup(HasStatus, HasObjective, CanArchive, AbstractCrudObject):

Expand All @@ -1187,11 +1204,9 @@ class Field(HasBidInfo, object):
conversion_specs = 'conversion_specs'
created_time = 'created_time'
creative = 'creative'
creative_ids = 'creative_ids'
failed_delivery_checks = 'failed_delivery_checks'
id = 'id'
name = 'name'
objective = 'objective'
redownload = 'redownload'
social_prefs = 'social_prefs'
status = 'adgroup_status'
Expand Down Expand Up @@ -1240,6 +1255,11 @@ def get_conversion_stats(self, fields=None, params=None):
"""Returns ConversionStats object associated with this ad."""
return self.edge_object(ConversionStats, fields, params)

def get_insights(self, fields=None, params=None):
params = params or {}
params['summary'] = params.get('summary')
return self.iterate_edge(Insights, fields, params)


class AdConversionPixel(AbstractCrudObject):

Expand Down Expand Up @@ -2037,7 +2057,7 @@ def get_endpoint(cls):
return 'transactions'


class Business(AbstractCrudObject, CannotCreate, CannotDelete):
class Business(CannotCreate, CannotDelete, AbstractCrudObject):

class Field(object):
created_by = 'created_by'
Expand All @@ -2053,6 +2073,11 @@ class Field(object):
def get_product_catalogs(self, fields=None, params=None):
return self.iterate_edge(ProductCatalog, fields, params)

def get_insights(self, fields=None, params=None):
params = params or {}
params['summary'] = params.get('summary')
return self.iterate_edge(Insights, fields, params)


class ProductCatalog(AbstractCrudObject):

Expand Down Expand Up @@ -2308,3 +2333,136 @@ class Field(object):
@classmethod
def get_endpoint(cls):
return 'product_audiences'


class Insights(CannotCreate, CannotDelete, CannotUpdate, AbstractCrudObject):
class Field(object):
account_id = 'account_id'
account_name = 'account_name'
action_values = 'action_values'
actions = 'actions'
actions_per_impression = 'actions_per_impression'
adgroup_id = 'adgroup_id'
adgroup_name = 'adgroup_name'
async_percent_completion = 'async_percent_completion'
async_status = 'async_status'
campaign_end = 'campaign_end'
campaign_group_end = 'campaign_group_end'
campaign_group_id = 'campaign_group_id'
campaign_group_name = 'campaign_group_name'
campaign_id = 'campaign_id'
campaign_name = 'campaign_name'
campaign_start = 'campaign_start'
clicks = 'clicks'
cost_per_action_type = 'cost_per_action_type'
cost_per_result = 'cost_per_result'
cost_per_total_action = 'cost_per_total_action'
cost_per_unique_click = 'cost_per_unique_click'
cpc = 'cpc'
cpm = 'cpm'
cpp = 'cpp'
ctr = 'ctr'
date_start = 'date_start'
date_stop = 'date_stop'
frequency = 'frequency'
id = 'id'
impressions = 'impressions'
objective = 'objective'
reach = 'reach'
relevance_score = 'relevance_score'
report_run_id = 'report_run_id'
result_rate = 'result_rate'
results = 'results'
roas = 'roas'
social_clicks = 'social_clicks'
social_impressions = 'social_impressions'
social_reach = 'social_reach'
spend = 'spend'
today_spend = 'today_spend'
total_action_value = 'total_action_value'
total_actions = 'total_actions'
total_unique_actions = 'total_unique_actions'
unique_clicks = 'unique_clicks'
unique_ctr = 'unique_ctr'
unique_social_clicks = 'unique_social_clicks'
video_avg_pct_watched_actions = 'video_avg_pct_watched_actions'
video_avg_sec_watched_actions = 'video_avg_sec_watched_actions'
video_complete_watched_actions = 'video_complete_watched_actions'
video_p100_watched_actions = 'video_p100_watched_actions'
video_p25_watched_actions = 'video_p25_watched_actions'
video_p50_watched_actions = 'video_p50_watched_actions'
video_p75_watched_actions = 'video_p75_watched_actions'
video_p95_watched_actions = 'video_p95_watched_actions'
video_start_actions = 'video_start_actions'

@classmethod
def get_endpoint(cls):
return 'insights'

class Preset(object):
last_14_days = 'last_14_days'
last_28_days = 'last_28_days'
last_30_days = 'last_30_days'
last_3_months = 'last_3_months'
last_week = 'last_week'
last_90_days = 'last_90_days'
last_month = 'last_month'
last_week = 'this_week'
this_month = 'this_month'
this_quarter = 'this_quarter'
today = 'today'
yesterday = 'yesterday'

class Increment(object):
monthly = 'monthly'
all_days = 'all_days'

class Breakdown(object):
age = 'age'
country = 'country'
gender = 'gender'
impression_device = 'impression_device'
placement = 'placement'

class Level(object):
account = 'account'
adgroup = 'adgroup'
campaign = 'campaign'
campaign_group = 'campaign_group'

class ActionBreakdown(object):
action_destination = 'action_destination'
action_device = 'action_device'
action_target_id = 'action_target_id'
action_type = 'action_type'
action_video_type = 'action_video_type'

class ActionAttributionWindow(object):
click_1d = '1d_click'
view_1d = '1d_view'
click_28d = '28d_click'
view_28d = '28d_view'
click_7d = '7d_click'
view_7d = '7d_view'
default = 'default'

class Operator(object):
all = 'all'
any = 'any'
contain = 'contain'
equal = 'equal'
greater_than = 'greater_than'
greater_than_or_equal = 'greater_than_or_equal'
in_ = 'in'
in_range = 'in_range'
less_than = 'less_than'
less_than_or_equal = 'less_than_or_equal'
none = 'none'
not_contain = 'not_contain'
not_equal = 'not_equal'
not_in = 'not_in'
not_in_range = 'not_in_range'

class ActionReportTime(object):
conversion = 'conversion'
impression = 'impression'
1 change: 1 addition & 0 deletions facebookads/specs.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ class Field(object):
image_crops = 'image_crops'
link = 'link'
message = 'message'
multi_share_optimized = 'multi_share_optimized'
name = 'name'
picture = 'picture'

Expand Down
36 changes: 13 additions & 23 deletions facebookads/test/integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -268,23 +268,6 @@ def assert_can_validate(cls, subject):
assert 'execution_options' not in subject
assert cached_data == subject._data

@classmethod
def assert_can_save(cls, subject):
"""
Asserts that the id is empty before creation and then updates
"""
assert subject[subject.Field.id] is None

subject.remote_save()

assert subject[subject.Field.id] is not None

subject.remote_save()

mirror = cls.get_mirror(subject)

assert subject[subject.Field.id] == mirror[mirror.Field.id]


class AdUserTestCase(AbstractCrudObjectTestCase):

Expand Down Expand Up @@ -369,8 +352,6 @@ def runTest(self):

self.assert_can_delete(self.subject)

self.assert_can_save(self.subject)


class GetByIDsTestCase(AbstractCrudObjectTestCase):

Expand Down Expand Up @@ -461,8 +442,6 @@ def runTest(self):

self.assert_can_delete(self.subject)

self.assert_can_save(self.subject)


class AdGroupTestCase(AbstractCrudObjectTestCase):

Expand Down Expand Up @@ -503,8 +482,6 @@ def runTest(self):

self.assert_can_delete(self.subject)

self.assert_can_save(self.subject)


class TargetingSearchTestCase(AbstractObjectTestCase):
def test_call(self):
Expand All @@ -525,6 +502,7 @@ def runTest(self):
self.delete_in_teardown(ca)
ca[objects.CustomAudience.Field.name] = \
'Custom Audience Test ' + self.TEST_ID
ca[objects.CustomAudience.Field.subtype] = 'CUSTOM'
ca.remote_create()

users = ['someone@example.com']
Expand Down Expand Up @@ -606,6 +584,18 @@ def test_can_read(self):
self.TEST_ACCOUNT.get_ad_images()


class InsightsTestCase(AbstractCrudObjectTestCase):
def test_can_read_without_job(self):
self.TEST_ACCOUNT.get_insights(fields=[
objects.Insights.Field.clicks,
objects.Insights.Field.impressions,
objects.Insights.Field.adgroup_id,
objects.Insights.Field.adgroup_name,
], params={
'level': objects.Insights.Level.adgroup,
})


class BatchTestCase(FacebookAdsTestCase):

def setUp(self):
Expand Down
2 changes: 1 addition & 1 deletion facebookads/video_uploader.py
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ def send_request(self, context):
).json()
self._start_offset = int(response['start_offset'])
self._end_offset = int(response['end_offset'])
except FacebookRequestError, e:
except FacebookRequestError as e:
subcode = e.api_error_subcode()
body = e.body()
if subcode == 1363037:
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
requirements_filename = os.path.join(this_dir, 'requirements.txt')

PACKAGE_NAME = 'facebookads'
PACKAGE_VERSION = '2.2.7'
PACKAGE_VERSION = '2.3.0'
PACKAGE_AUTHOR = 'Facebook'
PACKAGE_AUTHOR_EMAIL = ''
PACKAGE_URL = 'https://github.com/facebook/facebook-python-ads-sdk'
Expand Down

0 comments on commit 5679bbf

Please sign in to comment.