Skip to content

Commit d267d72

Browse files
Merge pull request #1 from anaconda/testing-ci
Testing and CI
2 parents 57f226d + ad4761e commit d267d72

File tree

9 files changed

+548
-33
lines changed

9 files changed

+548
-33
lines changed

.github/workflows/main.yml

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
name: Build and test
2+
on:
3+
push:
4+
branches:
5+
- main
6+
pull_request:
7+
branches:
8+
- main
9+
jobs:
10+
package:
11+
name: Build package
12+
runs-on: "ubuntu-latest"
13+
steps:
14+
- uses: actions/checkout@v2
15+
with:
16+
fetch-depth: 0
17+
- uses: conda-incubator/setup-miniconda@v2
18+
with:
19+
miniconda-version: "latest"
20+
activate-environment: build-intake-ga
21+
environment-file: etc/build-environment.yml
22+
python-version: 3.8
23+
auto-activate-base: false
24+
- name: Conda Build
25+
shell: bash -l {0}
26+
run: |
27+
conda build conda.recipe --no-test
28+
mv $CONDA_PREFIX/conda-bld .
29+
- name: Upload conda-bld directory
30+
uses: actions/upload-artifact@v2
31+
with:
32+
name: package-${{ github.sha }}
33+
path: ./conda-bld
34+
test:
35+
name: Test (${{ matrix.python-version }}, ${{ matrix.os }})
36+
runs-on: ${{ matrix.os }}
37+
strategy:
38+
fail-fast: false
39+
matrix:
40+
os: ["ubuntu-latest", "macos-latest", "windows-latest"]
41+
python-version: ["3.7", "3.8", "3.9"]
42+
steps:
43+
- uses: actions/checkout@v2
44+
- uses: conda-incubator/setup-miniconda@v2
45+
with:
46+
miniconda-version: "latest"
47+
python-version: ${{ matrix.python-version }}
48+
activate-environment: test-intake-ga
49+
environment-file: etc/test-environment.yml
50+
- name: Download the build artifact
51+
uses: actions/download-artifact@v2
52+
with:
53+
name: package-${{ github.sha }}
54+
path: ~/.conda/conda-bld
55+
- name: py.test
56+
shell: bash -l {0}
57+
run: |
58+
conda install -n test-intake-ga --use-local ~/.conda/conda-bld/noarch/intake-google-analytics-*.tar.bz2
59+
py.test -xv
60+
- name: Codecov
61+
uses: codecov/codecov-action@v1
62+
with:
63+
file: ./cov.xml
64+
env_vars: OS,PYTHON

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ nosetests.xml
4444
coverage.xml
4545
*,cover
4646
.hypothesis/
47+
junit.xml
48+
cov.xml
4749

4850
# Translations
4951
*.mo

environment.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ dependencies:
77
- pandas
88
- intake
99
- flake8
10+
- pytest
11+
- pytest-cov
1012
channels:
1113
- defaults
12-
- conda-forge
14+
- conda-forge

etc/build-environment.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
name: build-intake-ga
2+
dependencies:
3+
- conda
4+
- conda-build
5+
- conda-verify

etc/test-environment.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
name: test-intake-ga
2+
dependencies:
3+
- google-api-python-client
4+
- google-auth-oauthlib
5+
- pandas
6+
- intake
7+
- flake8
8+
- pytest
9+
- pytest-cov
10+
channels:
11+
- defaults
12+
- conda-forge

intake_google_analytics/source.py

Lines changed: 47 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
"INTEGER": int,
1818
"TIME": float,
1919
"PERCENT": float,
20-
"STRING": str,
20+
"FLOAT": float,
2121
"CURRENCY": float
2222
}
2323

@@ -90,51 +90,39 @@ def to_dask(self):
9090
raise NotImplementedError()
9191

9292
def _close(self):
93-
self._dataframe = None
93+
self._df = None
9494

9595

9696
class GoogleAnalyticsAPI(object):
97-
def __init__(self, credentials_path=None):
98-
credentials = None
99-
100-
if credentials_path:
101-
credentials = Credentials.from_service_account_file(credentials_path)
97+
def __init__(self, credentials_path):
98+
self._credentials_path = credentials_path
99+
self.client = self.create_client()
102100

103-
self.client = discovery.build('analyticsreporting', 'v4',
104-
credentials=credentials,
105-
cache_discovery=False).reports()
101+
def create_client(self):
102+
credentials = Credentials.from_service_account_file(self._credentials_path)
103+
c = discovery.build('analyticsreporting', 'v4',
104+
credentials=credentials,
105+
cache_discovery=False).reports()
106+
return c
106107

107-
def query(self, view_id: str, start_date: DateTypes, end_date: DateTypes, metrics: list,
108-
dimensions: list = None, filters: list = None):
108+
def query(self, view_id: str, start_date: DateTypes, end_date: DateTypes,
109+
metrics: list, dimensions: list = None, filters: list = None):
109110
result = self._query(
110111
view_id=view_id, start_date=start_date, end_date=end_date,
111112
metrics=metrics, dimensions=dimensions, filters=filters
112113
)
113114

114115
df = self._to_dataframe(result)
115-
116116
return df
117117

118-
def _query(self, view_id: str, start_date: DateTypes, end_date: DateTypes, metrics: list,
118+
def _build_body(self, view_id: str, start_date: DateTypes, end_date: DateTypes, metrics: list,
119119
dimensions: list = None, filters: list = None):
120120

121-
date_range = {'startDate': start_date, 'endDate': end_date}
122-
for key, value in date_range.items():
123-
if is_dt(value):
124-
date_range[key] = as_day(value)
125-
elif value.lower() in ['yesterday', 'today']:
126-
date_range[key] = value.lower()
127-
elif re.match(YYYY_MM_DD, value):
128-
pass
129-
elif re.match(r'\d+DaysAgo', value):
130-
pass
131-
else:
132-
raise ValueError(f'{key}={value} is not a supported date.\n'
133-
f'Please use a date/datetime object.')
134-
135-
body = {
136-
'reportRequests': []
121+
date_range = {
122+
'startDate': self._parse_date(start_date),
123+
'endDate': self._parse_date(end_date)
137124
}
125+
138126
request = {
139127
'viewId': view_id,
140128
'dateRanges': [date_range],
@@ -151,11 +139,23 @@ def _query(self, view_id: str, start_date: DateTypes, end_date: DateTypes, metri
151139
if filters:
152140
request['filtersExpression'] = filters
153141

154-
body['reportRequests'].append(request)
142+
body = {'reportRequests': [request]}
143+
return body
144+
145+
def _query(self, view_id: str, start_date: DateTypes, end_date: DateTypes, metrics: list,
146+
dimensions: list = None, filters: list = None):
147+
148+
body = self._build_body(
149+
view_id=view_id, start_date=start_date, end_date=end_date,
150+
metrics=metrics, dimensions=dimensions, filters=filters
151+
)
155152

156153
result = self.client.batchGet(body=body).execute()
154+
157155
report = result['reports'][0]
158-
expected_rows = report['data']['rowCount']
156+
expected_rows = report['data'].get('rowCount', 0)
157+
if expected_rows == 0:
158+
return report
159159

160160
while result['reports'][0].get('nextPageToken'):
161161
body['reportRequests'][0]['pageToken'] = result['reports'][0].get('nextPageToken')
@@ -238,3 +238,18 @@ def _parse_fields(fields, style):
238238
raise ValueError('\n'.join(errors))
239239

240240
return parsed
241+
242+
@staticmethod
243+
def _parse_date(value):
244+
if is_dt(value):
245+
return as_day(value)
246+
elif value in ['yesterday', 'today']:
247+
return value
248+
elif re.match(YYYY_MM_DD, value):
249+
return value
250+
elif re.match(r'\d+DaysAgo', value):
251+
return value
252+
else:
253+
raise ValueError(f'{value} is not a supported date.\n'
254+
f'Please use a date/datetime object or string of the following formats:\n'
255+
f'"yesterday", "today", "NDaysAgo", "YYYY-MM-DD"')

setup.cfg

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ addopts =
99
--junitxml=junit.xml
1010
--ignore setup.py
1111
--ignore run_test.py
12+
--cov=intake_google_analytics
13+
--cov-report=xml:cov.xml
1214
--cov-report term-missing
1315
--tb native
1416
--strict-markers

0 commit comments

Comments
 (0)