Skip to content

Commit

Permalink
package publish
Browse files Browse the repository at this point in the history
  • Loading branch information
KryeKuzhinieri committed Nov 2, 2022
0 parents commit 90acb02
Show file tree
Hide file tree
Showing 14 changed files with 522 additions and 0 deletions.
30 changes: 30 additions & 0 deletions .github/workflows/auto-release-to-github.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: "Release on GitHub"

on:
push:
branches:
- 'main'
workflow_dispatch:

jobs:
pre-release:
name: "Build and release on GitHub"
runs-on: "ubuntu-latest"
steps:
- uses: actions/checkout@master
- name: Set up Python 3.10
uses: actions/setup-python@v3
with:
python-version: "3.10"
- name: Install package.
run: |
python setup.py sdist --formats=gztar,zip
- uses: "marvinpinto/action-automatic-releases@latest"
with:
repo_token: "${{ secrets.GITHUB_TOKEN }}"
automatic_release_tag: "latest"
prerelease: true
title: "Development Build"
files: |
dist/*.tar.gz
dist/*.zip
37 changes: 37 additions & 0 deletions .github/workflows/publish-to-pypi.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: Publish Package 📦 to PyPI

on:
push:
branches:
- 'main'
workflow_dispatch:

jobs:
build-n-publish:
name: Build and publish package 📦 to PyPI.
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- name: Set up Python 3.10
uses: actions/setup-python@v3
with:
python-version: "3.10"
- name: Install pypa/build
run: >-
python -m
pip install
build
--user
- name: Build a binary wheel and a source tarball
run: >-
python -m
build
--sdist
--wheel
--outdir dist/
.
- name: Publish package 📦 to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
password: ${{ secrets.PYPI_API_TOKEN }}
skip_existing: true
41 changes: 41 additions & 0 deletions .github/workflows/test_package.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: Test Package

on: [workflow_dispatch, pull_request]

jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [macos-latest, windows-latest, ubuntu-latest]
python-version: ["2.7", "3.7", "3.8", "3.9", "3.10"]
steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies for python2
if: ${{ matrix.python-version < 3.0 }}
run: |
pip install flake8==2.6.2
pip install setuptools==2.0
pip install requests==2.25.1
- name: Install dependencies for python3
if: ${{ matrix.python-version >= 3.0 }}
run: pip install flake8
- name: Install PyWindsorAI
run: |
python setup.py install
echo "$(pip --version)"
echo "$(python --version)"
- 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: Unit Tests
run: python -m unittest discover test
env:
WINDSOR_TOKEN: ${{ secrets.WINDSOR_TOKEN }}
9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
ENV
__pycache__
.pyc
build
dist
.eggs
*.egg-info
*.local
.env
1 change: 1 addition & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include VERSION
145 changes: 145 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
# SnapchatAdsWindsorApi

`SnapchatAdsWindsorApi` is a python package makes it easy to get marketing data from Snapchat into python.

[Windsor.ai](https://windsor.ai/) allows to get marketing data from any platform. It simplifies the complexity of dealing with multiple platforms, unlocking unified, valuable information in a format that matters to you. For more details checkout [onboard.windsor.ai](https://onboard.windsor.ai/).

## Features

✅ Easy access to marketing data via windsor.ai APIs

✅ Lightweight (single dependency - [requests](https://pypi.org/project/requests/))

✅ Supports both python 2.7+ and 3

## Other Supported marketing and platforms

✅ Google Analytics

✅ Google Ads

✅ Facebook Ads

✅ Facebook organic

✅ Bing Ads

✅ Linkedin Ads

✅ Hubspot

✅ Salesforce

✅ Google search console

✅ Criteo

✅ Snapchat

✅ Tiktok

✅ Appnexus

✅ Campaign Manager

✅ Twitter

✅ Awin

✅ Adroll

✅ Shopify

✅ Klaviyo

✅ Airtable

✅ Intercom

✅ Zoho

✅ Idealo

✅ Pinterest

✅ Appsflyer

✅ Adobe





## Usage

### Installation

```sh
pip install SnapchatAdsWindsorApi
```

### Registration

You need to get a free API key to access windsor.ai's APIs. Register your account first and add a datasource like facebook ads and then get the API key. For more details check out our official [API documentation](https://windsor.ai/api-documentation/) and [this article](https://windsor.ai/api-fields/). Get the API key at https://onboard.windsor.ai

### Minimal Example

```python
from SnapchatAdsWindsorApi.client import Client
from SnapchatAdsWindsorApi.enums import LAST_7D
from SnapchatAdsWindsorApi.enums import FIELD_SOURCE, FIELD_CAMPAIGN, FIELD_CLICKS

api_key = 'xxx' # Get it from your windsor.ai account. It's recommended to store and get this securely, for example an env variable.

# Setup a client object with the API key
client = Client(api_key)

# Call the /connectors API.
campaign_clicks = client.connectors(date_preset=LAST_7D, fields=[FIELD_SOURCE, FIELD_CAMPAIGN, FIELD_CLICKS])

# can also be run like:
campaign_clicks = client.connectors(date_preset='last_7d', fields=['date','clicks','spend'])

# Response will be a python dict (parsed from the json response recieved).
print(campaign_clicks)

[
{'date': '2021-04-15', 'clicks': 3, 'spend': 8.139999999999999},
{'date': '2021-04-15', 'clicks': 2, 'spend': 6.51},
{'date': '2021-04-15', 'clicks': 1, 'spend': 3.88},
{'date': '2021-04-15', 'clicks': 4, 'spend': 3.275311},
{'date': '2021-04-15', 'clicks': 6, 'spend': 1.408321}
],

# Get Google Ads data only
campaign_clicks = client.connectors(
connector="google_ads",
date_preset=LAST_7D,
fields=["account_name", "campaign", "clicks", "datasource", "source", "spend"]
)

# Get Facebook Ads data only
campaign_clicks = client.connectors(
connector="facebook",
date_preset=LAST_7D,
fields=["account_name", "campaign", "clicks", "datasource", "source", "spend"]
)

# Get list of all possible connectors (i.e: Google Ads, Facebook Ads, Twitter, Tik Tok etc.)
list_connectors = client.list_connectors
print(list_connectors)

['adform', 'adobe', 'adroll', 'all', 'amazon_ads', 'amazon_s3', 'amazon_sp', 'apple_search_ads', 'appnexus', 'appsflyer', 'awin', 'bing', 'cm360', 'criteo' 'currency_conversion', 'daisycon', 'dv360', 'facebook', 'facebook_leads', 'facebook_organic', 'gmailcsv', 'google_ad_manager', 'google_ads', 'google_pagespeed', 'googleanalytics', 'googleanalytics4', 'googlesheets', 'hubspot', 'idealo', 'instagram', 'klaviyo', 'linkedin', 'linkedin_organic', 'mailchimp', 'outbrain', 'pinterest', 'quora', 'reddit', 'rtbhouse', 'salesforce', 'searchconsole', 'sftp', 'shopify', 'snapchat', 'stripe', 'taboola', 'tiktok', 'twitter', 'twitter_organic', 'vertaa', 'zoho']

# Sample with date specific ranges.
dataset_with_ranges = client.connectors(
date_from="2022-10-18",
date_to="2022-10-20",
fields=["account_name", "campaign", "clicks", "datasource", "source", "spend", "date"]
)
```

### List of fields
The full list of fields that the package accepts is given in https://windsor.ai/connector/all/. Fields can be common to all the connectors or specific for each company.


Empty file.
122 changes: 122 additions & 0 deletions SnapchatAdsWindsorApi/client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import requests
import time


class Client(object):
"""
Represents an API Client object for windsor.ai's APIs.
"""

API_URL = 'https://connectors.windsor.ai'

def __init__(self, api_key):

self.API_KEY = api_key
self.session = self._init_session()
self.status_code = None

def _init_session(self):

session = requests.session()
session.headers.update({
'Accept': 'application/json',
'User-Agent': 'windsorai/python'
})
return session

def _close_session(self):
self.session.close()

def _create_api_uri(self, path):
return self.API_URL + '/' + path

def _request(self, method, path, signed, **kwargs):
uri = self._create_api_uri(path)

kwargs['params']['api_key'] = self.API_KEY

response = getattr(self.session, method)(uri, **kwargs)
return self._handle_response(response)

def _handle_response(self, response):
"""
Internal helper for handling API responses from the windsor.ai server.
Raises the appropriate exceptions when necessary; otherwise, returns the
response.
Parameters
----------
response : requests.Response Object
Returns
-------
dictionary
Dictionary of the response object.
"""

# Any windsor.ai specific error handling can be done here
# Nothing as such for now
self.status_code = response.status_code
self._close_session()
return response.json()

def _get(self, path, signed=False, **kwargs):
return self._request('get', path, signed, **kwargs)

def _post(self, path, signed=False, **kwargs):
return self._request('post', path, signed, **kwargs)

def _put(self, path, signed=False, **kwargs):
return self._request('put', path, signed, **kwargs)

def _delete(self, path, signed=False, **kwargs):
return self._request('delete', path, signed, **kwargs)

# General Endpoints

@property
def list_connectors(self):
"""
Fetch list of all possible connectors.
This function returns all the available connectors from Windsor.ai
platform. The list can be found in the following website:
https://windsor.ai/connector/all/
Parameters
----------
Returns
-------
list
List of strings for all available connectors.
"""
return self._get(path="list_connectors", params={})

def connectors(self, connector="snapchat", **params):
"""
Fetch data from Windsor.ai
Get data from one of the available windsor connectors.
https://connectors.windsor.ai/#operations-default-get_connector
Parameters
----------
connector : str
A string with the preferred connector. Default - "all"
date_preset : str
It's recommended that you use provided enums, instead of a
hardcoded string. Example: LAST_7D
fields : list
List of fields. It's recommended that you use FIELD_* enums,
instead of hardcoded strings.
Example: [FIELD_SOURCE, FIELD_CAMPAIGN, FIELD_CLICKS].
Returns
-------
dictionary
Dictionary with the available data. In case of error, it returns
the error message.
Examples
--------
>>> from SnapchatAdsWindsorApi.enums import LAST_7D
>>> from SnapchatAdsWindsorApi.fields import FIELD_SOURCE, FIELD_CAMPAIGN, FIELD_CLICKS
>>> client = Client(api_key)
>>> orders = client.connectors(date_preset=LAST_7D, fields=[FIELD_SOURCE, FIELD_CAMPAIGN, FIELD_CLICKS])
"""
# Python interface is a list. Whereas the API expects a comma seperated string.
params['fields'] = ','.join(params['fields'])

return self._get(connector, params=params)
Loading

0 comments on commit 90acb02

Please sign in to comment.