Skip to content
This repository was archived by the owner on Jun 11, 2024. It is now read-only.

Commit 6387df2

Browse files
committed
add report
1 parent a8ef93d commit 6387df2

6 files changed

Lines changed: 119 additions & 7 deletions

File tree

README.rst

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,23 @@ Example Usage:
5858
print(publisher) # now all publisher data is there
5959
6060
61+
# reporting example
62+
# get a report for a specific publisher
63+
report = atomx.report(type='publisher', sums=['impressions', 'clicks'], groups=['hour'], where=[['publisher_id', '==', 42]], from_='2015-02-08 00:00:00Z', to='2015-02-09 00:00:00Z')
64+
# check if report is ready
65+
print(report.is_ready)
66+
# if pandas is installed you can get the pandas dataframe with `report.pandas`
67+
# you can also get the report csv in `report.content` without pandas
68+
df = report.pandas
69+
# set index to datetime
70+
import pandas as pd
71+
df.index = pd.to_datetime(df.pop('hour'))
72+
# resample per day
73+
means = df.resample('D', how=['mean', 'median', 'std'])
74+
# and plot impression and clicks per day
75+
means['impressions'].plot()
76+
means['clicks'].plot()
77+
6178
6279
Installation
6380
------------
@@ -68,3 +85,8 @@ To install the python atomx api, simply:
6885
6986
$ pip install atomx
7087
88+
or if you want to use ipython notebook and reporting functionality:
89+
90+
.. code-block:: bash
91+
92+
$ pip install atomx[report]

atomx/__init__.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,36 @@ def search(self, query):
5757
for v in search_result[m]]
5858
return search_result
5959

60+
def report(self, **kwargs):
61+
kwargs['from'] = kwargs['from_']
62+
del kwargs['from_']
63+
r = self.session.post(self.api_endpoint + 'report', json=kwargs)
64+
if not r.ok:
65+
raise APIError(r.json()['error'])
66+
return models.Report(self, query=r.json()['query'], **r.json()['report'])
67+
68+
def report_status(self, report):
69+
if isinstance(report, models.Report):
70+
report_id = report.id
71+
else:
72+
report_id = report
73+
74+
r = self.session.get(self.api_endpoint + 'report/' + report_id, params={'status': True})
75+
if not r.ok:
76+
raise APIError(r.json()['error'])
77+
return r.json()['report']
78+
79+
def report_get(self, report):
80+
if isinstance(report, models.Report):
81+
report_id = report.id
82+
else:
83+
report_id = report
84+
85+
r = self.session.get(self.api_endpoint + 'report/' + report_id)
86+
if not r.ok:
87+
raise APIError(r.json()['error'])
88+
return r.content.decode()
89+
6090
def get(self, resource, **kwargs):
6191
r = self.session.get(self.api_endpoint + resource, params=kwargs)
6292
if not r.ok:

atomx/exceptions.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,9 @@ class APIError(Exception):
99

1010
class ModelNotFoundError(Exception):
1111
pass
12+
13+
class ReportNotReadyError(Exception):
14+
pass
15+
16+
class NoPandasInstalledError(Exception):
17+
pass

atomx/models.py

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,17 @@
11
# -*- coding: utf-8 -*-
22

33
import pprint
4-
from .exceptions import NoSessionError, ModelNotFoundError, APIError
4+
try: # py3
5+
from io import StringIO
6+
except ImportError: # py2
7+
from StringIO import StringIO
8+
from .exceptions import (
9+
NoSessionError,
10+
ModelNotFoundError,
11+
APIError,
12+
ReportNotReadyError,
13+
NoPandasInstalledError,
14+
)
515

616
__all__ = ['Advertiser', 'Bidder', 'Browser', 'Campaign', 'Category', 'ConnectionType',
717
'ConversionPixel', 'Country', 'Creative', 'Datacenter', 'DeviceType',
@@ -94,3 +104,45 @@ def reload(self, session=None):
94104

95105
for m in __all__:
96106
locals()[m] = type(m, (AtomxModel,), {})
107+
108+
109+
class Report(object):
110+
def __init__(self, session, id, fast, status, lines, query, **kwargs):
111+
self.session = session
112+
self.id = id
113+
self.fast = fast
114+
self.status = status
115+
self.lines = lines
116+
self.query = query
117+
118+
@property
119+
def is_ready(self):
120+
if hasattr(self, '_is_ready'):
121+
return self._is_ready
122+
report_status = self.session.report_status(self)
123+
self.status = report_status['status']
124+
self.lines = report_status['lines']
125+
if self.status == 'SUCCESS':
126+
setattr(self, '_is_ready', True)
127+
return True
128+
elif self.status == 'ERROR':
129+
setattr(self, '_is_ready', True)
130+
return False
131+
132+
@property
133+
def content(self):
134+
if not self.is_ready:
135+
raise ReportNotReadyError()
136+
return self.session.report_get(self)
137+
138+
@property
139+
def pandas(self):
140+
try:
141+
import pandas as pd
142+
except ImportError:
143+
raise NoPandasInstalledError('To get the report as a pandas dataframe you '
144+
'have to have pandas installed. '
145+
'Do `pip install pandas` in your command line.')
146+
147+
return pd.read_csv(StringIO(self.content),
148+
names=self.query.get('groups', []) + self.query.get('sums', []))

setup.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@
1515
requires = [
1616
'requests',
1717
]
18+
extra_require={
19+
'report': ['ipython[notebook]', 'pandas', 'matplotlib'],
20+
'test': ['pytest'],
21+
'docs': ['sphinx'],
22+
}
1823

1924
setup(
2025
name='atomx',
@@ -42,8 +47,5 @@
4247
keywords='atomx rest api',
4348

4449
install_requires=requires,
45-
extra_require={
46-
'test': 'pytest',
47-
'docs': 'sphinx',
48-
}
50+
extra_require=extra_require,
4951
)

tests.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
@pytest.fixture(scope="session")
55
def atomx():
6-
from .atomx import Atomx
6+
from atomx import Atomx
77
return Atomx('daniel@atomx.com', 'password', 'http://127.0.0.1:6543/v1/')
88

99

@@ -21,7 +21,7 @@ def test_update(atomx):
2121

2222

2323
def test_save(atomx):
24-
from .atomx.models import Profile
24+
from atomx.models import Profile
2525
profile = Profile(advertiser_id=23, name='test advertiser')
2626
profile.save()
2727
profile_new = atomx.get(Profile, id=profile.id)

0 commit comments

Comments
 (0)