From 9fce5de027aed83a28fed8359ad5c07666eba365 Mon Sep 17 00:00:00 2001 From: Brad Pitcher Date: Mon, 15 May 2017 15:30:56 -0700 Subject: [PATCH 1/6] some general upgrades - Drop Python 2.6/3.2, support Pypy3, Python3.6 - Upgrade requirements - Simply travis/tox config --- .travis.yml | 20 +++++++------------- requirements/base.txt | 8 ++++---- requirements/test.txt | 6 +++--- setup.py | 6 +++--- tox.ini | 23 +---------------------- 5 files changed, 18 insertions(+), 45 deletions(-) diff --git a/.travis.yml b/.travis.yml index 56ed8ba..95d0494 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,16 +1,10 @@ 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: + - 2.7 + - 3.3 + - 3.4 + - 3.5 install: - - pip install coveralls tox -script: tox -e $TOX_ENV + - pip install coveralls tox-travis +script: tox after_success: coveralls diff --git a/requirements/base.txt b/requirements/base.txt index c6902f6..42a8ca9 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -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 diff --git a/requirements/test.txt b/requirements/test.txt index a7dda87..cc83ad5 100644 --- a/requirements/test.txt +++ b/requirements/test.txt @@ -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 diff --git a/setup.py b/setup.py index ba252b1..cdd03c6 100644 --- a/setup.py +++ b/setup.py @@ -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", ] ) diff --git a/tox.ini b/tox.ini index dba5950..36213ca 100644 --- a/tox.ini +++ b/tox.ini @@ -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 From 953a93618f782b43eda53f8917fb644877489227 Mon Sep 17 00:00:00 2001 From: Brad Pitcher Date: Mon, 15 May 2017 15:49:30 -0700 Subject: [PATCH 2/6] add pypy,pypy3 and 3.6 to travis matrix --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index 95d0494..145f2d2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,12 @@ language: python python: + - pypy + - pypy3 - 2.7 - 3.3 - 3.4 - 3.5 + - 3.6 install: - pip install coveralls tox-travis script: tox From 1cef3ca54d9b3fd25ad8d7498408e7ee378d0faf Mon Sep 17 00:00:00 2001 From: Brad Pitcher Date: Mon, 15 May 2017 15:54:17 -0700 Subject: [PATCH 3/6] fix flake8 issues --- withings/__init__.py | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/withings/__init__.py b/withings/__init__.py index 3ad090f..b5a7bab 100644 --- a/withings/__init__.py +++ b/withings/__init__.py @@ -41,7 +41,6 @@ import requests from arrow.parser import ParserError -from datetime import datetime from requests_oauthlib import OAuth1, OAuth1Session @@ -82,11 +81,13 @@ 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'], + ) class WithingsApi(object): @@ -173,15 +174,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) From b987333daf55d2fb46ade5ddb95a390058e786fa Mon Sep 17 00:00:00 2001 From: Brad Pitcher Date: Mon, 15 May 2017 15:56:00 -0700 Subject: [PATCH 4/6] fix pypy3 travis tests --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 145f2d2..219cc33 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,7 @@ language: python python: - pypy - - pypy3 + - pypy3.3-5.2-alpha1 - 2.7 - 3.3 - 3.4 From 4855f3d385b75c6c0736e2a5344285d6d2d752c3 Mon Sep 17 00:00:00 2001 From: Brad Pitcher Date: Mon, 15 May 2017 17:25:25 -0700 Subject: [PATCH 5/6] more flake8 fixes --- tests/test_withings_api.py | 8 ++------ tests/test_withings_measures.py | 2 +- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/tests/test_withings_api.py b/tests/test_withings_api.py index 10018cc..f1ea7d7 100644 --- a/tests/test_withings_api.py +++ b/tests/test_withings_api.py @@ -1,8 +1,6 @@ import json -import time import unittest -from datetime import datetime from requests import Session from withings import ( WithingsActivity, @@ -31,7 +29,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'), @@ -146,7 +144,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 @@ -288,7 +285,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 @@ -340,7 +336,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') diff --git a/tests/test_withings_measures.py b/tests/test_withings_measures.py index 29be22e..2311567 100644 --- a/tests/test_withings_measures.py +++ b/tests/test_withings_measures.py @@ -1,8 +1,8 @@ -import time import unittest from withings import WithingsMeasureGroup, WithingsMeasures + class TestWithingsMeasures(unittest.TestCase): def test_withings_measures_init(self): """ From 90a12811c06097179fb35affc20c63c1d3c364d5 Mon Sep 17 00:00:00 2001 From: Brad Pitcher Date: Tue, 16 May 2017 07:07:10 -0700 Subject: [PATCH 6/6] convert date-like objects to timestamp integer for API calls --- tests/test_withings_api.py | 32 ++++++++++++++++++++++++++++++++ withings/__init__.py | 17 ++++++++++++++--- 2 files changed, 46 insertions(+), 3 deletions(-) diff --git a/tests/test_withings_api.py b/tests/test_withings_api.py index f1ea7d7..e30a033 100644 --- a/tests/test_withings_api.py +++ b/tests/test_withings_api.py @@ -1,3 +1,5 @@ +import arrow +import datetime import json import unittest @@ -237,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 diff --git a/withings/__init__.py b/withings/__init__.py index b5a7bab..e3809c5 100644 --- a/withings/__init__.py +++ b/withings/__init__.py @@ -37,6 +37,7 @@ str('WithingsMeasures'), str('WithingsMeasureGroup')] import arrow +import datetime import json import requests @@ -90,6 +91,14 @@ def get_credentials(self, oauth_verifier): ) +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): URL = 'http://wbsapi.withings.net' @@ -106,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()) @@ -163,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)