Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 10 additions & 13 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
language: python
python: 3.5
env:
# Avoid testing pypy on travis until the following issue is fixed:
# https://github.com/travis-ci/travis-ci/issues/4756
#- TOX_ENV=pypy
- TOX_ENV=py35
- TOX_ENV=py34
- TOX_ENV=py33
- TOX_ENV=py32
- TOX_ENV=py27
- TOX_ENV=py26
python:
- pypy
- pypy3.3-5.2-alpha1
- 2.7
- 3.3
- 3.4
- 3.5
- 3.6
install:
- pip install coveralls tox
script: tox -e $TOX_ENV
- pip install coveralls tox-travis
script: tox
after_success: coveralls
8 changes: 4 additions & 4 deletions requirements/base.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
arrow>=0.4,<0.8
requests>=2.5,<2.9
requests-oauth>=0.4.1,<0.5
requests-oauthlib>=0.4.2,<0.6
arrow>=0.4
requests>=2.5
requests-oauth>=0.4.1
requests-oauthlib>=0.4.2
6 changes: 3 additions & 3 deletions requirements/test.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
-r base.txt

coverage>=3.7,<4.0
mock>=1.0,<1.4
tox>=1.8,<2.2
coverage>=3.7
mock>=1.0
tox>=1.8
6 changes: 3 additions & 3 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,14 @@
"Intended Audience :: Developers",
"Programming Language :: Python",
"Programming Language :: Python :: 2",
"Programming Language :: Python :: 2.6",
"Programming Language :: Python :: 2.7",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.2",
"Programming Language :: Python :: 3.3",
"Programming Language :: Python :: 3.4",
"Programming Language :: Python :: 3.5",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: Implementation",
"Programming Language :: Python :: Implementation :: PyPy"
"Programming Language :: Python :: Implementation :: CPython",
"Programming Language :: Python :: Implementation :: PyPy",
]
)
40 changes: 34 additions & 6 deletions tests/test_withings_api.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import arrow
import datetime
import json
import time
import unittest

from datetime import datetime
from requests import Session
from withings import (
WithingsActivity,
Expand Down Expand Up @@ -31,7 +31,7 @@ def setUp(self):
if self.mock_api:
self.creds = WithingsCredentials()
else:
config = ConfigParser.ConfigParser()
config = configparser.ConfigParser()
config.read('withings.conf')
self.creds = WithingsCredentials(
consumer_key=config.get('withings', 'consumer_key'),
Expand Down Expand Up @@ -146,7 +146,6 @@ def test_get_sleep(self):
body['series'][0]['enddate'])
self.assertEqual(resp.series[1].state, 1)


def test_get_activities(self):
"""
Check that get_activities fetches the appropriate URL, the response
Expand Down Expand Up @@ -240,6 +239,36 @@ def test_get_measures(self):
self.assertEqual(len(resp), 1)
self.assertEqual(resp[0].weight, 86.0)

def test_get_measures_lastupdate_date(self):
"""Check that dates get converted to timestampse for API calls"""
self.mock_request({'updatetime': 1409596058, 'measuregrps': []})

self.api.get_measures(lastupdate=datetime.date(2014, 9, 1))

Session.request.assert_called_once_with(
'GET', 'http://wbsapi.withings.net/measure',
params={'action': 'getmeas', 'lastupdate': 1409529600})

def test_get_measures_lastupdate_datetime(self):
"""Check that datetimes get converted to timestampse for API calls"""
self.mock_request({'updatetime': 1409596058, 'measuregrps': []})

self.api.get_measures(lastupdate=datetime.datetime(2014, 9, 1))

Session.request.assert_called_once_with(
'GET', 'http://wbsapi.withings.net/measure',
params={'action': 'getmeas', 'lastupdate': 1409529600})

def test_get_measures_lastupdate_arrow(self):
"""Check that arrow dates get converted to timestampse for API calls"""
self.mock_request({'updatetime': 1409596058, 'measuregrps': []})

self.api.get_measures(lastupdate=arrow.get('2014-09-01'))

Session.request.assert_called_once_with(
'GET', 'http://wbsapi.withings.net/measure',
params={'action': 'getmeas', 'lastupdate': 1409529600})

def test_subscribe(self):
"""
Check that subscribe fetches the right URL and returns the expected
Expand Down Expand Up @@ -288,7 +317,6 @@ def test_unsubscribe(self):
'callbackurl': 'http://www.example.com/'})
self.assertEqual(resp, None)


def test_is_subscribed(self):
"""
Check that is_subscribed fetches the right URL and returns the
Expand Down Expand Up @@ -340,7 +368,7 @@ def test_list_subscriptions(self):
def mock_request(self, body, status=0):
if self.mock_api:
json_content = {'status': status}
if body != None:
if body is not None:
json_content['body'] = body
response = MagicMock()
response.content = json.dumps(json_content).encode('utf8')
Expand Down
2 changes: 1 addition & 1 deletion tests/test_withings_measures.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import time
import unittest

from withings import WithingsMeasureGroup, WithingsMeasures


class TestWithingsMeasures(unittest.TestCase):
def test_withings_measures_init(self):
"""
Expand Down
23 changes: 1 addition & 22 deletions tox.ini
Original file line number Diff line number Diff line change
@@ -1,27 +1,6 @@
[tox]
envlist = pypy,py35,py34,py33,py32,py27,py26
envlist = pypy,pypy3,py36,py35,py34,py33,py27

[testenv]
commands = coverage run --branch --source=withings setup.py test
deps = -r{toxinidir}/requirements/test.txt

[testenv:pypy]
basepython = pypy

[testenv:py35]
basepython = python3.5

[testenv:py34]
basepython = python3.4

[testenv:py33]
basepython = python3.3

[testenv:py32]
basepython = python3.2

[testenv:py27]
basepython = python2.7

[testenv:py26]
basepython = python2.6
47 changes: 33 additions & 14 deletions withings/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,11 @@
str('WithingsMeasures'), str('WithingsMeasureGroup')]

import arrow
import datetime
import json
import requests

from arrow.parser import ParserError
from datetime import datetime
from requests_oauthlib import OAuth1, OAuth1Session


Expand Down Expand Up @@ -82,11 +82,21 @@ def get_credentials(self, oauth_verifier):
resource_owner_secret=self.oauth_secret,
verifier=oauth_verifier)
tokens = oauth.fetch_access_token('%s/access_token' % self.URL)
return WithingsCredentials(access_token=tokens['oauth_token'],
access_token_secret=tokens['oauth_token_secret'],
consumer_key=self.consumer_key,
consumer_secret=self.consumer_secret,
user_id=tokens['userid'])
return WithingsCredentials(
access_token=tokens['oauth_token'],
access_token_secret=tokens['oauth_token_secret'],
consumer_key=self.consumer_key,
consumer_secret=self.consumer_secret,
user_id=tokens['userid'],
)


def is_date(key):
return 'date' in key


def is_date_class(val):
return isinstance(val, (datetime.date, datetime.datetime, arrow.Arrow, ))


class WithingsApi(object):
Expand All @@ -105,9 +115,11 @@ def __init__(self, credentials):

def request(self, service, action, params=None, method='GET',
version=None):
if params is None:
params = {}
params = params or {}
params['action'] = action
for key, val in params.items():
if is_date(key) and is_date_class(val):
params[key] = arrow.get(val).timestamp
url_parts = filter(None, [self.URL, version, service])
r = self.client.request(method, '/'.join(url_parts), params=params)
response = json.loads(r.content.decode())
Expand Down Expand Up @@ -162,7 +174,7 @@ def set_attributes(self, data):
self.data = data
for key, val in data.items():
try:
setattr(self, key, arrow.get(val) if 'date' in key else val)
setattr(self, key, arrow.get(val) if is_date(key) else val)
except ParserError:
setattr(self, key, val)

Expand All @@ -173,15 +185,22 @@ class WithingsActivity(WithingsObject):

class WithingsMeasures(list, WithingsObject):
def __init__(self, data):
super(WithingsMeasures, self).__init__([WithingsMeasureGroup(g) for g in data['measuregrps']])
super(WithingsMeasures, self).__init__(
[WithingsMeasureGroup(g) for g in data['measuregrps']])
self.set_attributes(data)


class WithingsMeasureGroup(WithingsObject):
MEASURE_TYPES = (('weight', 1), ('height', 4), ('fat_free_mass', 5),
('fat_ratio', 6), ('fat_mass_weight', 8),
('diastolic_blood_pressure', 9), ('systolic_blood_pressure', 10),
('heart_pulse', 11))
MEASURE_TYPES = (
('weight', 1),
('height', 4),
('fat_free_mass', 5),
('fat_ratio', 6),
('fat_mass_weight', 8),
('diastolic_blood_pressure', 9),
('systolic_blood_pressure', 10),
('heart_pulse', 11),
)

def __init__(self, data):
super(WithingsMeasureGroup, self).__init__(data)
Expand Down