From 0afe9511a975894d309fd76e2510c49e3638d892 Mon Sep 17 00:00:00 2001 From: Tushar Bhushan Date: Mon, 10 Feb 2020 11:49:12 -0800 Subject: [PATCH 01/14] Create pythonpublish.yml Testing CI/CD integration --- .github/workflows/pythonpublish.yml | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 .github/workflows/pythonpublish.yml diff --git a/.github/workflows/pythonpublish.yml b/.github/workflows/pythonpublish.yml new file mode 100644 index 0000000..b143a53 --- /dev/null +++ b/.github/workflows/pythonpublish.yml @@ -0,0 +1,26 @@ +name: Upload Python Package + +on: + release: + types: [created] + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Set up Python + uses: actions/setup-python@v1 + with: + python-version: '3.x' + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install setuptools wheel twine + - name: Build and publish + env: + TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }} + TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }} + run: | + python setup.py sdist bdist_wheel + twine upload dist/* From 638267501bb0708eb1314f843e26b66c724af6eb Mon Sep 17 00:00:00 2001 From: Tushar Bhushan Date: Mon, 10 Feb 2020 13:55:01 -0800 Subject: [PATCH 02/14] Update pythonpublish.yml --- .github/workflows/pythonpublish.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pythonpublish.yml b/.github/workflows/pythonpublish.yml index b143a53..33c8ebc 100644 --- a/.github/workflows/pythonpublish.yml +++ b/.github/workflows/pythonpublish.yml @@ -1,4 +1,4 @@ -name: Upload Python Package +name: Update PyPi on: release: From ef98d73cba6d10e1465978eeecad936e59bc9342 Mon Sep 17 00:00:00 2001 From: Tushar Bhushan Date: Mon, 10 Feb 2020 13:58:09 -0800 Subject: [PATCH 03/14] Update __init__.py --- twitter_ads/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/twitter_ads/__init__.py b/twitter_ads/__init__.py index 00f34fa..3c9d0a6 100644 --- a/twitter_ads/__init__.py +++ b/twitter_ads/__init__.py @@ -1,6 +1,6 @@ # Copyright (C) 2015 Twitter, Inc. -VERSION = (6, 1, 0) +VERSION = (6, 1, 1) API_VERSION = '6' from twitter_ads.utils import get_version From 7de97b5640ddde5cf3baf01677ec7ab8128475c5 Mon Sep 17 00:00:00 2001 From: Tushar Bhushan Date: Mon, 10 Feb 2020 14:02:59 -0800 Subject: [PATCH 04/14] Update __init__.py --- twitter_ads/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/twitter_ads/__init__.py b/twitter_ads/__init__.py index 3c9d0a6..00f34fa 100644 --- a/twitter_ads/__init__.py +++ b/twitter_ads/__init__.py @@ -1,6 +1,6 @@ # Copyright (C) 2015 Twitter, Inc. -VERSION = (6, 1, 1) +VERSION = (6, 1, 0) API_VERSION = '6' from twitter_ads.utils import get_version From a78076de67197566b777a72e36adea4bcb4c39d9 Mon Sep 17 00:00:00 2001 From: Tushar Bhushan Date: Mon, 5 Oct 2020 13:10:38 -0700 Subject: [PATCH 05/14] Create python-package.yml --- .github/workflows/python-package.yml | 39 ++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 .github/workflows/python-package.yml diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml new file mode 100644 index 0000000..f1abc2f --- /dev/null +++ b/.github/workflows/python-package.yml @@ -0,0 +1,39 @@ +# This workflow will install Python dependencies, run tests and lint with a variety of Python versions +# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions + +name: Python package + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + build: + + runs-on: ubuntu-latest + strategy: + matrix: + python-version: [3.5, 3.6, 3.7, 3.8] + + steps: + - uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install flake8 pytest + if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + - name: Lint with flake8 + run: | + # stop the build if there are Python syntax errors or undefined names + flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics + # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide + flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics + - name: Test with pytest + run: | + pytest From 4e0cabd1db1f1359efc525d7ff512e45edf82c1a Mon Sep 17 00:00:00 2001 From: Tushar Bhushan Date: Mon, 5 Oct 2020 13:15:19 -0700 Subject: [PATCH 06/14] Update python-package.yml --- .github/workflows/python-package.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index f1abc2f..f2dded5 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -31,9 +31,10 @@ jobs: - name: Lint with flake8 run: | # stop the build if there are Python syntax errors or undefined names - flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics + # flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide - flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics + # flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics + python setup.py flake8 - name: Test with pytest run: | - pytest + python setup.py test From 4206d23508dea19020a73efbb482801bc3b95c18 Mon Sep 17 00:00:00 2001 From: Tushar Bhushan Date: Mon, 5 Oct 2020 13:24:15 -0700 Subject: [PATCH 07/14] Update python-package.yml --- .github/workflows/python-package.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index f2dded5..897b795 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: [3.5, 3.6, 3.7, 3.8] + python-version: [pypy, pypy2, pypy3, 3.5, 3.6, 3.7, 3.8] steps: - uses: actions/checkout@v2 From 3739defcd72c2d22821e84d7ffab0b7bc884b0f1 Mon Sep 17 00:00:00 2001 From: Tushar Bhushan Date: Mon, 5 Oct 2020 13:26:50 -0700 Subject: [PATCH 08/14] Update python-package.yml --- .github/workflows/python-package.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index 897b795..a6eab83 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -12,10 +12,11 @@ on: jobs: build: - runs-on: ubuntu-latest + runs-on: ${{ matrix.os }} strategy: matrix: - python-version: [pypy, pypy2, pypy3, 3.5, 3.6, 3.7, 3.8] + python-version: [pypy2, pypy3, 3.5, 3.6, 3.7, 3.8] + os: [macos-latest, windows-latest, ubuntu-latest] steps: - uses: actions/checkout@v2 From 8f25cecaf51dd1053eabe6ee7095985b270b9f38 Mon Sep 17 00:00:00 2001 From: Tushar Bhushan Date: Mon, 5 Oct 2020 13:32:00 -0700 Subject: [PATCH 09/14] removed windows --- .github/workflows/python-package.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index a6eab83..85eb065 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -16,7 +16,7 @@ jobs: strategy: matrix: python-version: [pypy2, pypy3, 3.5, 3.6, 3.7, 3.8] - os: [macos-latest, windows-latest, ubuntu-latest] + os: [macos-latest, ubuntu-latest] steps: - uses: actions/checkout@v2 From e6dda1d74cae2d7c75486118f4c98e3ff1808ee8 Mon Sep 17 00:00:00 2001 From: Tushar Bhushan Date: Mon, 5 Oct 2020 13:51:52 -0700 Subject: [PATCH 10/14] removed python 3.8 --- .github/workflows/python-package.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index 85eb065..bdfdda8 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -15,7 +15,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - python-version: [pypy2, pypy3, 3.5, 3.6, 3.7, 3.8] + python-version: [pypy2, pypy3, 3.5, 3.6, 3.7] os: [macos-latest, ubuntu-latest] steps: From 80e1edb78f9f9a0f9dcc51e2526f7f421e3bdf0e Mon Sep 17 00:00:00 2001 From: Tushar Bhushan Date: Mon, 5 Oct 2020 14:18:53 -0700 Subject: [PATCH 11/14] Update python-package.yml --- .github/workflows/python-package.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index bdfdda8..b832bc3 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -15,7 +15,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - python-version: [pypy2, pypy3, 3.5, 3.6, 3.7] + python-version: [pypy, pypy2, pypy3, 3.5, 3.6, 3.7] os: [macos-latest, ubuntu-latest] steps: From 7488d8488d4125920ab38f8e5357cbcd51b766ec Mon Sep 17 00:00:00 2001 From: Tushar Bhushan Date: Mon, 5 Oct 2020 14:32:53 -0700 Subject: [PATCH 12/14] remove pypy --- .github/workflows/python-package.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index b832bc3..bdfdda8 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -15,7 +15,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - python-version: [pypy, pypy2, pypy3, 3.5, 3.6, 3.7] + python-version: [pypy2, pypy3, 3.5, 3.6, 3.7] os: [macos-latest, ubuntu-latest] steps: From 30f6eaa6ea426e3f9b9209605aa862b31e3e8ca7 Mon Sep 17 00:00:00 2001 From: Tushar Bhushan Date: Mon, 5 Oct 2020 14:39:03 -0700 Subject: [PATCH 13/14] Update python-package.yml --- .github/workflows/python-package.yml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index bdfdda8..2a7e337 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -1,7 +1,7 @@ # This workflow will install Python dependencies, run tests and lint with a variety of Python versions # For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions -name: Python package +name: Python build on: push: @@ -31,10 +31,6 @@ jobs: if [ -f requirements.txt ]; then pip install -r requirements.txt; fi - name: Lint with flake8 run: | - # stop the build if there are Python syntax errors or undefined names - # flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics - # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide - # flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics python setup.py flake8 - name: Test with pytest run: | From b8613dbef8f80a780f5ccf6e0fc6bbc3689c5f9d Mon Sep 17 00:00:00 2001 From: Tushar Bhushan Date: Mon, 10 Feb 2020 11:49:12 -0800 Subject: [PATCH 14/14] Create pythonpublish.yml Testing CI/CD integration Update pythonpublish.yml Update __init__.py Update __init__.py Add github actions (#249) * Added pythonpublish.yml to auto-deploy to PyPi on new release Ads API v7 (#251) * Removed scoped timeline endpoint * added granular tap placements * added advertiser business categories endpoint * updated serving_status to entity_status for media creatives * replaced reach estimate with audience summary * added audience summary and tests Add header for internal use (#252) * add internal header Bump version (#253) Merge across forks to get CI working (#265) (#266) * Add store identifiers to line item * bump version Create python-package.yml Update python-package.yml Update python-package.yml Update python-package.yml removed windows removed python 3.8 Update python-package.yml remove pypy Update python-package.yml --- .github/workflows/python-package.yml | 37 ++++++++++++++++ .github/workflows/pythonpublish.yml | 26 ++++++++++++ examples/audience_summary.py | 40 ++++++++++++++++++ requirements.txt | 3 ++ tests/fixtures/audience_summary.json | 14 +++++++ tests/test_audience_summary.py | 63 ++++++++++++++++++++++++++++ twitter_ads/__init__.py | 4 +- twitter_ads/account.py | 18 -------- twitter_ads/campaign.py | 13 ++++++ twitter_ads/client.py | 6 +++ twitter_ads/creative.py | 2 +- twitter_ads/enum.py | 7 +++- twitter_ads/http.py | 6 ++- twitter_ads/targeting.py | 25 +++++++---- 14 files changed, 232 insertions(+), 32 deletions(-) create mode 100644 .github/workflows/python-package.yml create mode 100644 .github/workflows/pythonpublish.yml create mode 100644 examples/audience_summary.py create mode 100644 tests/fixtures/audience_summary.json create mode 100644 tests/test_audience_summary.py diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml new file mode 100644 index 0000000..2a7e337 --- /dev/null +++ b/.github/workflows/python-package.yml @@ -0,0 +1,37 @@ +# This workflow will install Python dependencies, run tests and lint with a variety of Python versions +# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions + +name: Python build + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + build: + + runs-on: ${{ matrix.os }} + strategy: + matrix: + python-version: [pypy2, pypy3, 3.5, 3.6, 3.7] + os: [macos-latest, ubuntu-latest] + + steps: + - uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install flake8 pytest + if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + - name: Lint with flake8 + run: | + python setup.py flake8 + - name: Test with pytest + run: | + python setup.py test diff --git a/.github/workflows/pythonpublish.yml b/.github/workflows/pythonpublish.yml new file mode 100644 index 0000000..33c8ebc --- /dev/null +++ b/.github/workflows/pythonpublish.yml @@ -0,0 +1,26 @@ +name: Update PyPi + +on: + release: + types: [created] + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Set up Python + uses: actions/setup-python@v1 + with: + python-version: '3.x' + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install setuptools wheel twine + - name: Build and publish + env: + TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }} + TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }} + run: | + python setup.py sdist bdist_wheel + twine upload dist/* diff --git a/examples/audience_summary.py b/examples/audience_summary.py new file mode 100644 index 0000000..5f0bdcd --- /dev/null +++ b/examples/audience_summary.py @@ -0,0 +1,40 @@ +from twitter_ads.client import Client +from twitter_ads.targeting import AudienceSummary + +CONSUMER_KEY = 'your consumer key' +CONSUMER_SECRET = 'your consumer secret' +ACCESS_TOKEN = 'access token' +ACCESS_TOKEN_SECRET = 'access token secret' +ACCOUNT_ID = 'account id' + +# initialize the client +client = Client(CONSUMER_KEY, CONSUMER_SECRET, ACCESS_TOKEN, ACCESS_TOKEN_SECRET) + +# load the advertiser account instance +account = client.accounts(ACCOUNT_ID) + +# targeting criteria params +params = { + "targeting_criteria": [ + { + "targeting_type":"LOCATION", + "targeting_value":"96683cc9126741d1" + }, + { + "targeting_type":"BROAD_KEYWORD", + "targeting_value":"cats" + }, + { + "targeting_type":"SIMILAR_TO_FOLLOWERS_OF_USER", + "targeting_value": "14230524" + }, + { + "targeting_type":"SIMILAR_TO_FOLLOWERS_OF_USER", + "targeting_value": "90420314" + } + ] +} + +audience_summary = AudienceSummary.load(account=account, params=params) + +print (audience_summary.audience_size) diff --git a/requirements.txt b/requirements.txt index 3e9aab1..111c2e4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,3 +4,6 @@ python-dateutil responses mock setuptools_scm +MarkupSafe +setuptools>=40.0 +configparser>=3.5 \ No newline at end of file diff --git a/tests/fixtures/audience_summary.json b/tests/fixtures/audience_summary.json new file mode 100644 index 0000000..e8dd488 --- /dev/null +++ b/tests/fixtures/audience_summary.json @@ -0,0 +1,14 @@ +{ + "request": { + "params": { + "targeting_criteria": null, + "account_id": "2iqph" + } + }, + "data": { + "audience_size": { + "min": 41133600, + "max": 50274400 + } + } +} \ No newline at end of file diff --git a/tests/test_audience_summary.py b/tests/test_audience_summary.py new file mode 100644 index 0000000..20bfa67 --- /dev/null +++ b/tests/test_audience_summary.py @@ -0,0 +1,63 @@ +import responses +import unittest + +from tests.support import with_resource, with_fixture, characters + +from twitter_ads.account import Account +from twitter_ads.client import Client +from twitter_ads.targeting import AudienceSummary +from twitter_ads import API_VERSION + + +@responses.activate +def test_audience_summary(): + 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/audience_summary'), + body=with_fixture('audience_summary'), + content_type='application/json') + + client = Client( + characters(40), + characters(40), + characters(40), + characters(40) + ) + + account = Account.load(client, '2iqph') + + params = { + "targeting_criteria": [ + { + "targeting_type":"LOCATION", + "targeting_value":"96683cc9126741d1" + }, + { + "targeting_type":"BROAD_KEYWORD", + "targeting_value":"cats" + }, + { + "targeting_type":"SIMILAR_TO_FOLLOWERS_OF_USER", + "targeting_value": "14230524" + }, + { + "targeting_type":"SIMILAR_TO_FOLLOWERS_OF_USER", + "targeting_value": "90420314" + } + ] + } + + audience_summary = AudienceSummary.load( + account=account, + params=params + ) + + print (audience_summary) + assert audience_summary is not None + assert audience_summary.audience_size is not None + assert audience_summary.audience_size['min'] == 41133600 + assert audience_summary.audience_size['max'] == 50274400 diff --git a/twitter_ads/__init__.py b/twitter_ads/__init__.py index 00f34fa..b5fe98f 100644 --- a/twitter_ads/__init__.py +++ b/twitter_ads/__init__.py @@ -1,7 +1,7 @@ # Copyright (C) 2015 Twitter, Inc. -VERSION = (6, 1, 0) -API_VERSION = '6' +VERSION = (7, 0, 2) +API_VERSION = '7' from twitter_ads.utils import get_version diff --git a/twitter_ads/account.py b/twitter_ads/account.py index 3534979..0bd4344 100644 --- a/twitter_ads/account.py +++ b/twitter_ads/account.py @@ -6,7 +6,6 @@ from twitter_ads.enum import TRANSFORM from twitter_ads.http import Request from twitter_ads.cursor import Cursor -from twitter_ads.utils import Deprecated from twitter_ads import API_VERSION from twitter_ads.resource import resource_property, Resource @@ -28,7 +27,6 @@ class Account(Resource): RESOURCE_COLLECTION = '/' + API_VERSION + '/accounts' RESOURCE = '/' + API_VERSION + '/accounts/{id}' FEATURES = '/' + API_VERSION + '/accounts/{id}/features' - SCOPED_TIMELINE = '/5/accounts/{id}/scoped_timeline' def __init__(self, client): self._client = client @@ -156,22 +154,6 @@ def video_website_cards(self, id=None, **kwargs): """ return self._load_resource(VideoWebsiteCard, id, **kwargs) - @Deprecated('This method has been deprecated as of version 5' - 'and no longer works in the latest version.') - def scoped_timeline(self, *id, **kwargs): - """ - Returns the most recent promotable Tweets created by the specified Twitter user. - """ - self._validate_loaded() - - params = {'user_id': id} - params.update(kwargs) - - resource = self.SCOPED_TIMELINE.format(id=self.id) - response = Request(self.client, 'get', resource, params=params).perform() - - return response.body['data'] - # account properties resource_property(Account, 'id', readonly=True) diff --git a/twitter_ads/campaign.py b/twitter_ads/campaign.py index be934cc..20a88e5 100644 --- a/twitter_ads/campaign.py +++ b/twitter_ads/campaign.py @@ -298,6 +298,8 @@ def save(self): resource_property(LineItem, 'charge_by') resource_property(LineItem, 'end_time', transform=TRANSFORM.TIME) resource_property(LineItem, 'entity_status') +resource_property(LineItem, 'ios_app_store_identifier') +resource_property(LineItem, 'android_app_store_identifier') resource_property(LineItem, 'audience_expansion') resource_property(LineItem, 'name') resource_property(LineItem, 'objective') @@ -470,3 +472,14 @@ class IabCategories(Resource): resource_property(IabCategories, 'id', readonly=True) resource_property(IabCategories, 'name', readonly=True) resource_property(IabCategories, 'parent_id', readonly=True) + + +class AdvertiserBusinessCategories(Resource): + + PROPERTIES = {} + RESOURCE_COLLECTION = '/' + API_VERSION + '/advertiser_business_categories' + + +resource_property(ContentCategories, 'id', readonly=True) +resource_property(ContentCategories, 'name', readonly=True) +resource_property(ContentCategories, 'iab_categories', readonly=True) diff --git a/twitter_ads/client.py b/twitter_ads/client.py index 6b91a5c..47b625d 100644 --- a/twitter_ads/client.py +++ b/twitter_ads/client.py @@ -29,6 +29,7 @@ def __init__(self, self._access_token = access_token self._access_token_secret = access_token_secret self._options = kwargs.get('options', {}) + self._headers = kwargs.get('headers', {}) def __repr__(self): return '<{name} object at {mem} consumer_key={key}>'.format( @@ -42,6 +43,11 @@ def options(self): """Returns the options value.""" return self._options + @property + def headers(self): + """Returns the headers value.""" + return self._headers + @property def consumer_key(self): """Returns the consumer_key value.""" diff --git a/twitter_ads/creative.py b/twitter_ads/creative.py index 87023d7..aafd6de 100644 --- a/twitter_ads/creative.py +++ b/twitter_ads/creative.py @@ -117,7 +117,7 @@ class MediaCreative(Analytics, Resource, Persistence): resource_property(MediaCreative, 'created_at', readonly=True, transform=TRANSFORM.TIME) resource_property(MediaCreative, 'deleted', readonly=True, transform=TRANSFORM.BOOL) resource_property(MediaCreative, 'id', readonly=True) -resource_property(MediaCreative, 'serving_status', readonly=True) +resource_property(MediaCreative, 'entity_status', readonly=True) resource_property(MediaCreative, 'updated_at', readonly=True, transform=TRANSFORM.TIME) # writable resource_property(MediaCreative, 'account_media_id') diff --git a/twitter_ads/enum.py b/twitter_ads/enum.py index 722dd76..28f5567 100644 --- a/twitter_ads/enum.py +++ b/twitter_ads/enum.py @@ -155,7 +155,12 @@ def enum(**enums): ALL_ON_TWITTER='ALL_ON_TWITTER', TWITTER_SEARCH='TWITTER_SEARCH', TWITTER_TIMELINE='TWITTER_TIMELINE', - PUBLISHER_NETWORK='PUBLISHER_NETWORK' + PUBLISHER_NETWORK='PUBLISHER_NETWORK', + TAP_FULL='TAP_FULL', + TAP_FULL_LANDSCAPE='TAP_FULL_LANDSCAPE', + TAP_BANNER='TAP_BANNER', + TAP_NATIVE='TAP_NATIVE', + TAP_MRECT="TAP_MRECT" ) PRODUCT = enum( diff --git a/twitter_ads/http.py b/twitter_ads/http.py index 1931f12..c7e15b8 100644 --- a/twitter_ads/http.py +++ b/twitter_ads/http.py @@ -75,10 +75,12 @@ def __oauth_request(self): if 'headers' in self.options: headers.update(self.options['headers'].copy()) - # internal-only + # DEPRECATED: internal-only (Should pass a header to the client) if 'x-as-user' in self._client.options: headers['x-as-user'] = self._client.options.get('x-as-user') - + # Add headers from the client to the request (Client headers take priority) + for key, val in self._client.headers.items(): + headers[key] = val params = self.options.get('params', None) data = self.options.get('body', None) files = self.options.get('files', None) diff --git a/twitter_ads/targeting.py b/twitter_ads/targeting.py index 621425c..b185ba0 100644 --- a/twitter_ads/targeting.py +++ b/twitter_ads/targeting.py @@ -3,19 +3,28 @@ """Container for all targeting related logic used by the Ads API SDK.""" from twitter_ads.http import Request +from twitter_ads.resource import resource_property, Resource, Persistence from twitter_ads import API_VERSION +from twitter_ads.utils import FlattenParams +import json -class ReachEstimate(object): +class AudienceSummary(Resource, Persistence): + PROPERTIES = {} - RESOURCE = '/' + API_VERSION + '/accounts/{account_id}/reach_estimate' + RESOURCE = '/' + API_VERSION + '/accounts/{account_id}/audience_summary' @classmethod - def fetch(klass, account, product_type, objective, user_id, **kwargs): - params = {'product_type': product_type, 'objective': objective, 'user_id': user_id} - params.update(kwargs) - + @FlattenParams + def load(klass, account, params): resource = klass.RESOURCE.format(account_id=account.id) - response = Request(account.client, 'get', resource, params=params).perform() + headers = {'Content-Type': 'application/json'} + response = Request(account.client, + 'post', + resource, + headers=headers, + body=json.dumps(params)).perform() + return klass(account).from_response(response.body['data']) + - return response.body['data'] +resource_property(AudienceSummary, 'audience_size')