Skip to content

Commit 5679bbf

Browse files
author
Evan Chen
committed
Insights and minor changes for v2.3
Summary: Added insights edge and bumped version for v2.3 Test Plan: Run tests tox python -m facebookads.test.integration
1 parent c03fbcf commit 5679bbf

File tree

6 files changed

+180
-31
lines changed

6 files changed

+180
-31
lines changed

facebookads/api.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,9 +129,9 @@ class FacebookAdsApi(object):
129129
this sdk.
130130
"""
131131

132-
SDK_VERSION = '2.2.7'
132+
SDK_VERSION = '2.3.0'
133133

134-
API_VERSION = 'v2.2'
134+
API_VERSION = 'v2.3'
135135

136136
HTTP_METHOD_GET = 'GET'
137137

facebookads/objects.py

Lines changed: 162 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,8 @@ def load_next_page(self):
127127
if self._finished_iteration:
128128
return False
129129

130-
self._params['summary'] = True
130+
if 'summary' not in self._params:
131+
self._params['summary'] = True
131132

132133
response = self._source_object.get_api_assured().call(
133134
'GET',
@@ -804,6 +805,7 @@ class Field(object):
804805
agency_client_declaration = 'agency_client_declaration'
805806
amount_spent = 'amount_spent'
806807
balance = 'balance'
808+
business = 'business'
807809
business_city = 'business_city'
808810
business_country_code = 'business_country_code'
809811
business_name = 'business_name'
@@ -941,6 +943,11 @@ def get_ad_images(self, fields=None, params=None):
941943
"""Returns iterator over AdImage's associated with this account."""
942944
return self.iterate_edge(AdImage, fields, params)
943945

946+
def get_insights(self, fields=None, params=None):
947+
params = params or {}
948+
params['summary'] = params.get('summary')
949+
return self.iterate_edge(Insights, fields, params)
950+
944951
def get_broad_category_targeting(self, fields=None, params=None):
945952
"""
946953
Returns iterator over BroadCategoryTargeting's associated with this
@@ -1125,6 +1132,11 @@ def get_stats(self, fields=None, params=None):
11251132
"""Returns iterator over AdStat's associated with this campaign."""
11261133
return self.iterate_edge(AdStats, fields, params)
11271134

1135+
def get_insights(self, fields=None, params=None):
1136+
params = params or {}
1137+
params['summary'] = params.get('summary')
1138+
return self.iterate_edge(Insights, fields, params)
1139+
11281140

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

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

1190+
def get_insights(self, fields=None, params=None):
1191+
params = params or {}
1192+
params['summary'] = params.get('summary')
1193+
return self.iterate_edge(Insights, fields, params)
1194+
11781195

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

@@ -1187,11 +1204,9 @@ class Field(HasBidInfo, object):
11871204
conversion_specs = 'conversion_specs'
11881205
created_time = 'created_time'
11891206
creative = 'creative'
1190-
creative_ids = 'creative_ids'
11911207
failed_delivery_checks = 'failed_delivery_checks'
11921208
id = 'id'
11931209
name = 'name'
1194-
objective = 'objective'
11951210
redownload = 'redownload'
11961211
social_prefs = 'social_prefs'
11971212
status = 'adgroup_status'
@@ -1240,6 +1255,11 @@ def get_conversion_stats(self, fields=None, params=None):
12401255
"""Returns ConversionStats object associated with this ad."""
12411256
return self.edge_object(ConversionStats, fields, params)
12421257

1258+
def get_insights(self, fields=None, params=None):
1259+
params = params or {}
1260+
params['summary'] = params.get('summary')
1261+
return self.iterate_edge(Insights, fields, params)
1262+
12431263

12441264
class AdConversionPixel(AbstractCrudObject):
12451265

@@ -2037,7 +2057,7 @@ def get_endpoint(cls):
20372057
return 'transactions'
20382058

20392059

2040-
class Business(AbstractCrudObject, CannotCreate, CannotDelete):
2060+
class Business(CannotCreate, CannotDelete, AbstractCrudObject):
20412061

20422062
class Field(object):
20432063
created_by = 'created_by'
@@ -2053,6 +2073,11 @@ class Field(object):
20532073
def get_product_catalogs(self, fields=None, params=None):
20542074
return self.iterate_edge(ProductCatalog, fields, params)
20552075

2076+
def get_insights(self, fields=None, params=None):
2077+
params = params or {}
2078+
params['summary'] = params.get('summary')
2079+
return self.iterate_edge(Insights, fields, params)
2080+
20562081

20572082
class ProductCatalog(AbstractCrudObject):
20582083

@@ -2308,3 +2333,136 @@ class Field(object):
23082333
@classmethod
23092334
def get_endpoint(cls):
23102335
return 'product_audiences'
2336+
2337+
2338+
class Insights(CannotCreate, CannotDelete, CannotUpdate, AbstractCrudObject):
2339+
class Field(object):
2340+
account_id = 'account_id'
2341+
account_name = 'account_name'
2342+
action_values = 'action_values'
2343+
actions = 'actions'
2344+
actions_per_impression = 'actions_per_impression'
2345+
adgroup_id = 'adgroup_id'
2346+
adgroup_name = 'adgroup_name'
2347+
async_percent_completion = 'async_percent_completion'
2348+
async_status = 'async_status'
2349+
campaign_end = 'campaign_end'
2350+
campaign_group_end = 'campaign_group_end'
2351+
campaign_group_id = 'campaign_group_id'
2352+
campaign_group_name = 'campaign_group_name'
2353+
campaign_id = 'campaign_id'
2354+
campaign_name = 'campaign_name'
2355+
campaign_start = 'campaign_start'
2356+
clicks = 'clicks'
2357+
cost_per_action_type = 'cost_per_action_type'
2358+
cost_per_result = 'cost_per_result'
2359+
cost_per_total_action = 'cost_per_total_action'
2360+
cost_per_unique_click = 'cost_per_unique_click'
2361+
cpc = 'cpc'
2362+
cpm = 'cpm'
2363+
cpp = 'cpp'
2364+
ctr = 'ctr'
2365+
date_start = 'date_start'
2366+
date_stop = 'date_stop'
2367+
frequency = 'frequency'
2368+
id = 'id'
2369+
impressions = 'impressions'
2370+
objective = 'objective'
2371+
reach = 'reach'
2372+
relevance_score = 'relevance_score'
2373+
report_run_id = 'report_run_id'
2374+
result_rate = 'result_rate'
2375+
results = 'results'
2376+
roas = 'roas'
2377+
social_clicks = 'social_clicks'
2378+
social_impressions = 'social_impressions'
2379+
social_reach = 'social_reach'
2380+
spend = 'spend'
2381+
today_spend = 'today_spend'
2382+
total_action_value = 'total_action_value'
2383+
total_actions = 'total_actions'
2384+
total_unique_actions = 'total_unique_actions'
2385+
unique_clicks = 'unique_clicks'
2386+
unique_ctr = 'unique_ctr'
2387+
unique_social_clicks = 'unique_social_clicks'
2388+
video_avg_pct_watched_actions = 'video_avg_pct_watched_actions'
2389+
video_avg_sec_watched_actions = 'video_avg_sec_watched_actions'
2390+
video_complete_watched_actions = 'video_complete_watched_actions'
2391+
video_p100_watched_actions = 'video_p100_watched_actions'
2392+
video_p25_watched_actions = 'video_p25_watched_actions'
2393+
video_p50_watched_actions = 'video_p50_watched_actions'
2394+
video_p75_watched_actions = 'video_p75_watched_actions'
2395+
video_p95_watched_actions = 'video_p95_watched_actions'
2396+
video_start_actions = 'video_start_actions'
2397+
2398+
@classmethod
2399+
def get_endpoint(cls):
2400+
return 'insights'
2401+
2402+
class Preset(object):
2403+
last_14_days = 'last_14_days'
2404+
last_28_days = 'last_28_days'
2405+
last_30_days = 'last_30_days'
2406+
last_3_months = 'last_3_months'
2407+
last_week = 'last_week'
2408+
last_90_days = 'last_90_days'
2409+
last_month = 'last_month'
2410+
last_week = 'this_week'
2411+
this_month = 'this_month'
2412+
this_quarter = 'this_quarter'
2413+
today = 'today'
2414+
yesterday = 'yesterday'
2415+
2416+
class Increment(object):
2417+
monthly = 'monthly'
2418+
all_days = 'all_days'
2419+
2420+
class Breakdown(object):
2421+
age = 'age'
2422+
country = 'country'
2423+
gender = 'gender'
2424+
impression_device = 'impression_device'
2425+
placement = 'placement'
2426+
2427+
class Level(object):
2428+
account = 'account'
2429+
adgroup = 'adgroup'
2430+
campaign = 'campaign'
2431+
campaign_group = 'campaign_group'
2432+
2433+
class ActionBreakdown(object):
2434+
action_destination = 'action_destination'
2435+
action_device = 'action_device'
2436+
action_target_id = 'action_target_id'
2437+
action_type = 'action_type'
2438+
action_video_type = 'action_video_type'
2439+
2440+
class ActionAttributionWindow(object):
2441+
click_1d = '1d_click'
2442+
view_1d = '1d_view'
2443+
click_28d = '28d_click'
2444+
view_28d = '28d_view'
2445+
click_7d = '7d_click'
2446+
view_7d = '7d_view'
2447+
default = 'default'
2448+
2449+
class Operator(object):
2450+
all = 'all'
2451+
any = 'any'
2452+
contain = 'contain'
2453+
equal = 'equal'
2454+
greater_than = 'greater_than'
2455+
greater_than_or_equal = 'greater_than_or_equal'
2456+
in_ = 'in'
2457+
in_range = 'in_range'
2458+
less_than = 'less_than'
2459+
less_than_or_equal = 'less_than_or_equal'
2460+
none = 'none'
2461+
not_contain = 'not_contain'
2462+
not_equal = 'not_equal'
2463+
not_in = 'not_in'
2464+
not_in_range = 'not_in_range'
2465+
2466+
class ActionReportTime(object):
2467+
conversion = 'conversion'
2468+
impression = 'impression'

facebookads/specs.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ class Field(object):
5757
image_crops = 'image_crops'
5858
link = 'link'
5959
message = 'message'
60+
multi_share_optimized = 'multi_share_optimized'
6061
name = 'name'
6162
picture = 'picture'
6263

facebookads/test/integration.py

Lines changed: 13 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -268,23 +268,6 @@ def assert_can_validate(cls, subject):
268268
assert 'execution_options' not in subject
269269
assert cached_data == subject._data
270270

271-
@classmethod
272-
def assert_can_save(cls, subject):
273-
"""
274-
Asserts that the id is empty before creation and then updates
275-
"""
276-
assert subject[subject.Field.id] is None
277-
278-
subject.remote_save()
279-
280-
assert subject[subject.Field.id] is not None
281-
282-
subject.remote_save()
283-
284-
mirror = cls.get_mirror(subject)
285-
286-
assert subject[subject.Field.id] == mirror[mirror.Field.id]
287-
288271

289272
class AdUserTestCase(AbstractCrudObjectTestCase):
290273

@@ -369,8 +352,6 @@ def runTest(self):
369352

370353
self.assert_can_delete(self.subject)
371354

372-
self.assert_can_save(self.subject)
373-
374355

375356
class GetByIDsTestCase(AbstractCrudObjectTestCase):
376357

@@ -461,8 +442,6 @@ def runTest(self):
461442

462443
self.assert_can_delete(self.subject)
463444

464-
self.assert_can_save(self.subject)
465-
466445

467446
class AdGroupTestCase(AbstractCrudObjectTestCase):
468447

@@ -503,8 +482,6 @@ def runTest(self):
503482

504483
self.assert_can_delete(self.subject)
505484

506-
self.assert_can_save(self.subject)
507-
508485

509486
class TargetingSearchTestCase(AbstractObjectTestCase):
510487
def test_call(self):
@@ -525,6 +502,7 @@ def runTest(self):
525502
self.delete_in_teardown(ca)
526503
ca[objects.CustomAudience.Field.name] = \
527504
'Custom Audience Test ' + self.TEST_ID
505+
ca[objects.CustomAudience.Field.subtype] = 'CUSTOM'
528506
ca.remote_create()
529507

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

608586

587+
class InsightsTestCase(AbstractCrudObjectTestCase):
588+
def test_can_read_without_job(self):
589+
self.TEST_ACCOUNT.get_insights(fields=[
590+
objects.Insights.Field.clicks,
591+
objects.Insights.Field.impressions,
592+
objects.Insights.Field.adgroup_id,
593+
objects.Insights.Field.adgroup_name,
594+
], params={
595+
'level': objects.Insights.Level.adgroup,
596+
})
597+
598+
609599
class BatchTestCase(FacebookAdsTestCase):
610600

611601
def setUp(self):

facebookads/video_uploader.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ def send_request(self, context):
217217
).json()
218218
self._start_offset = int(response['start_offset'])
219219
self._end_offset = int(response['end_offset'])
220-
except FacebookRequestError, e:
220+
except FacebookRequestError as e:
221221
subcode = e.api_error_subcode()
222222
body = e.body()
223223
if subcode == 1363037:

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
requirements_filename = os.path.join(this_dir, 'requirements.txt')
3030

3131
PACKAGE_NAME = 'facebookads'
32-
PACKAGE_VERSION = '2.2.7'
32+
PACKAGE_VERSION = '2.3.0'
3333
PACKAGE_AUTHOR = 'Facebook'
3434
PACKAGE_AUTHOR_EMAIL = ''
3535
PACKAGE_URL = 'https://github.com/facebook/facebook-python-ads-sdk'

0 commit comments

Comments
 (0)