Repository: orcasgit/python-nokia

Issue:
Add sleep summary API
We use this API in work, PR to follow.

Discussion:
coveralls: 
[![Coverage Status](https://coveralls.io/builds/19853184/badge)](https://coveralls.io/builds/19853184)

Coverage decreased (-1.08%) to 98.919% when pulling **f976667194fee3d6f4819e37b19c31f4c860a333 on yhvh:feature/WA-471-add-sleep-summary-to-python-nokia** into **fd4951da6bb51d2e2893339032207b96070c4c79 on orcasgit:master**.


Patch:
diff --git a/nokia/__init__.py b/nokia/__init__.py
index 007910a..9fcbf45 100644
--- a/nokia/__init__.py
+++ b/nokia/__init__.py
@@ -221,6 +221,10 @@ class NokiaApi(object):
         r = self.request('sleep', 'get', params=kwargs, version='v2')
         return NokiaSleep(r)
 
+    def get_sleep_summary(self, **kwargs):
+        r = self.request('sleep', 'getsummary', params=kwargs, version='v2')
+        return NokiaSleepSummary(r)
+
     def subscribe(self, callback_url, comment, **kwargs):
         params = {'callbackurl': callback_url, 'comment': comment}
         params.update(kwargs)
@@ -319,3 +323,17 @@ class NokiaSleep(NokiaObject):
     def __init__(self, data):
         super(NokiaSleep, self).__init__(data)
         self.series = [NokiaSleepSeries(series) for series in self.series]
+
+
+class NokiaSleepSummarySeries(NokiaObject):
+    def __init__(self, data):
+        _data = data
+        _data.update(_data.pop('data'))
+        super(NokiaSleepSummarySeries, self).__init__(_data)
+        self.timedelta = self.enddate - self.startdate
+
+
+class NokiaSleepSummary(NokiaObject):
+    def __init__(self, data):
+        super(NokiaSleepSummary, self).__init__(data)
+        self.series = [NokiaSleepSummarySeries(series) for series in self.series]


Test patch:
diff --git a/tests/__init__.py b/tests/__init__.py
index 9a23d19..7824abd 100644
--- a/tests/__init__.py
+++ b/tests/__init__.py
@@ -9,6 +9,8 @@ from .test_nokia_measures import TestNokiaMeasures
 from .test_nokia_object import TestNokiaObject
 from .test_nokia_sleep import TestNokiaSleep
 from .test_nokia_sleep_series import TestNokiaSleepSeries
+from .test_nokia_sleep_summary import TestNokiaSleepSummary
+from .test_nokia_sleep_summary_series import TestNokiaSleepSummarySeries
 
 
 def all_tests():
@@ -22,4 +24,6 @@ def all_tests():
     suite.addTest(unittest.makeSuite(TestNokiaObject))
     suite.addTest(unittest.makeSuite(TestNokiaSleep))
     suite.addTest(unittest.makeSuite(TestNokiaSleepSeries))
+    suite.addTest(unittest.makeSuite(TestNokiaSleepSummary))
+    suite.addTest(unittest.makeSuite(TestNokiaSleepSummarySeries))
     return suite
diff --git a/tests/test_nokia_api.py b/tests/test_nokia_api.py
index a5b26f7..85848e4 100644
--- a/tests/test_nokia_api.py
+++ b/tests/test_nokia_api.py
@@ -11,7 +11,9 @@ from nokia import (
     NokiaMeasureGroup,
     NokiaMeasures,
     NokiaSleep,
-    NokiaSleepSeries
+    NokiaSleepSeries,
+    NokiaSleepSummary,
+    NokiaSleepSummarySeries,
 )
 
 try:
@@ -233,6 +235,70 @@ class TestNokiaApi(unittest.TestCase):
                          body['series'][0]['enddate'])
         self.assertEqual(resp.series[1].state, 1)
 
+    def test_get_sleep_summary(self):
+        """
+        Check that get_sleep_summary fetches the appropriate URL, the response looks
+        correct, and the return value is a NokiaSleepSummary object with the
+        correct attributes
+        """
+        body = {
+            'more': False,
+            'series': [
+                {
+                    'data': {
+                        'deepsleepduration': 18660,
+                        'durationtosleep': 0,
+                        'durationtowakeup': 240,
+                        'lightsleepduration': 20220,
+                        'wakeupcount': 1,
+                        'wakeupduration': 720
+                    },
+                    'date': '2018-10-30',
+                    'enddate': 1540897020,
+                    'id': 900363515,
+                    'model': 16,
+                    'modified': 1540897246,
+                    'startdate': 1540857420,
+                    'timezone': 'Europe/London'
+                },
+                {
+                    'data': {
+                        'deepsleepduration': 17040,
+                        'durationtosleep': 360,
+                        'durationtowakeup': 0,
+                        'lightsleepduration': 10860,
+                        'wakeupcount': 1,
+                        'wakeupduration': 540
+                    },
+                    'date': '2018-10-31',
+                    'enddate': 1540973400,
+                    'id': 901269807,
+                    'model': 16,
+                    'modified': 1541020749,
+                    'startdate': 1540944960,
+                    'timezone': 'Europe/London'
+                }
+            ]
+        }
+        self.mock_request(body)
+        resp = self.api.get_sleep_summary()
+        Session.request.assert_called_once_with(
+            'GET',
+            self._req_url('https://wbsapi.withings.net/v2/sleep'),
+            **self._req_kwargs({'action': 'getsummary'})
+        )
+        self.assertEqual(type(resp), NokiaSleepSummary)
+        self.assertEqual(type(resp.series), list)
+        self.assertEqual(len(resp.series), 2)
+        self.assertEqual(type(resp.series[0]), NokiaSleepSummarySeries)
+        self.assertEqual(resp.series[0].model, body['series'][0]['model'])
+        self.assertEqual(resp.series[0].startdate.timestamp,
+                         body['series'][0]['startdate'])
+        self.assertEqual(resp.series[0].enddate.timestamp,
+                         body['series'][0]['enddate'])
+        self.assertEqual(resp.series[0].deepsleepduration,
+                         body['series'][0]['data']['deepsleepduration'])
+
     def test_get_activities(self):
         """
         Check that get_activities fetches the appropriate URL, the response
diff --git a/tests/test_nokia_sleep_summary.py b/tests/test_nokia_sleep_summary.py
new file mode 100644
index 0000000..40ea435
--- /dev/null
+++ b/tests/test_nokia_sleep_summary.py
@@ -0,0 +1,56 @@
+import time
+import unittest
+
+from nokia import NokiaSleepSummary, NokiaSleepSummarySeries
+
+
+class TestNokiaSleepSummary(unittest.TestCase):
+    def test_attributes(self):
+        data = {
+            'more': False,
+            'series': [
+                {
+                    'data': {
+                        'deepsleepduration': 18660,
+                        'durationtosleep': 0,
+                        'durationtowakeup': 240,
+                        'lightsleepduration': 20220,
+                        'wakeupcount': 1,
+                        'wakeupduration': 720
+                    },
+                    'date': '2018-10-30',
+                    'enddate': 1540897020,
+                    'id': 900363515,
+                    'model': 16,
+                    'modified': 1540897246,
+                    'startdate': 1540857420,
+                    'timezone': 'Europe/London'
+                },
+                {
+                    'data': {
+                        'deepsleepduration': 17040,
+                        'durationtosleep': 360,
+                        'durationtowakeup': 0,
+                        'lightsleepduration': 10860,
+                        'wakeupcount': 1,
+                        'wakeupduration': 540
+                    },
+                    'date': '2018-10-31',
+                    'enddate': 1540973400,
+                    'id': 901269807,
+                    'model': 16,
+                    'modified': 1541020749,
+                    'startdate': 1540944960,
+                    'timezone': 'Europe/London'
+                }
+            ]
+        }
+        sleep = NokiaSleepSummary(data)
+        self.assertEqual(sleep.series[0].model, data['series'][0]['model'])
+        self.assertEqual(type(sleep.series), list)
+        self.assertEqual(len(sleep.series), 2)
+        self.assertEqual(type(sleep.series[0]), NokiaSleepSummarySeries)
+        self.assertEqual(sleep.series[0].startdate.timestamp,
+                         data['series'][0]['startdate'])
+        self.assertEqual(sleep.series[0].enddate.timestamp,
+                         data['series'][0]['enddate'])
diff --git a/tests/test_nokia_sleep_summary_series.py b/tests/test_nokia_sleep_summary_series.py
new file mode 100644
index 0000000..83021cc
--- /dev/null
+++ b/tests/test_nokia_sleep_summary_series.py
@@ -0,0 +1,48 @@
+import time
+import unittest
+
+from datetime import timedelta
+from nokia import NokiaSleepSummarySeries
+
+
+class TestNokiaSleepSummarySeries(unittest.TestCase):
+    def test_attributes(self):
+        data = {
+            'data':  {
+                'deepsleepduration': 18660,
+                'durationtosleep': 0,
+                'durationtowakeup': 240,
+                'lightsleepduration': 20220,
+                'wakeupcount': 1,
+                'wakeupduration': 720,
+            },
+            'date': '2018-10-30',
+            'enddate': 1540897020,
+            'id': 900363515,
+            'model': 16,
+            'modified': 1540897246,
+            'startdate': 1540857420,
+            'timezone': 'Europe/London',
+        }
+        flat_data = {
+            'deepsleepduration': 18660,
+            'durationtosleep': 0,
+            'durationtowakeup': 240,
+            'lightsleepduration': 20220,
+            'wakeupcount': 1,
+            'wakeupduration': 720,
+            'date': '2018-10-30',
+            'enddate': 1540897020,
+            'id': 900363515,
+            'model': 16,
+            'modified': 1540897246,
+            'startdate': 1540857420,
+            'timezone': 'Europe/London',
+        }
+
+        series = NokiaSleepSummarySeries(data)
+        self.assertEqual(type(series), NokiaSleepSummarySeries)
+        self.assertEqual(series.startdate.timestamp, flat_data['startdate'])
+        self.assertEqual(series.data, flat_data)
+        self.assertEqual(series.enddate.timestamp, flat_data['enddate'])
+        self.assertEqual(series.timedelta, timedelta(seconds=39600))