Repository: jamesremuscat/pyze

Issue:
Show schedule throws exception
I do get a valid response, however, an exception is thrown. I am not so much a Python person, I assume you iterate over the weekdays and as it doesn't find "monday" in it, it fails.

````
{
    "data": {
        "type": "Car",
        "id": "VF1AG000*********",
        "attributes": {
            "mode": "always",
            "schedules": [{
                "id": 1,
                "activated": true,
                "thursday": {
                    "startTime": "T01:00Z",
                    "duration": 120
                }
            }, {
                "id": 2,
                "activated": false
            }, {
                "id": 3,
                "activated": false
            }, {
                "id": 4,
                "activated": false
            }, {
                "id": 5,
                "activated": false
            }]
        }
    }
}
````

Discussion:

Patch:
diff --git a/setup.cfg b/setup.cfg
index 940e03e..d7e2ad0 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -3,3 +3,6 @@ ignore = E501
 
 [tool:pytest]
 junit_family=xunit2
+filterwarnings =
+    ignore
+    default:::pyze
diff --git a/src/pyze/api/kamereon.py b/src/pyze/api/kamereon.py
index 30c53aa..8d3d0d2 100644
--- a/src/pyze/api/kamereon.py
+++ b/src/pyze/api/kamereon.py
@@ -245,7 +245,7 @@ class Vehicle(object):
     def lock_status(self):
         return self._get('lock-status')
 
-    # Not (currently) implemented server-side
+    # Not implemented server-side for most vehicles
     def location(self):
         return self._get('location')
 
diff --git a/src/pyze/api/schedule.py b/src/pyze/api/schedule.py
index 6e856ad..3d96677 100644
--- a/src/pyze/api/schedule.py
+++ b/src/pyze/api/schedule.py
@@ -18,7 +18,11 @@ DAYS = [
 def _parse_schedule(data):
     schedule = {}
     for day in DAYS:
-        schedule[day] = ScheduledCharge(data[day]['startTime'], data[day]['duration'])
+        if day in data:
+            schedule[day] = ScheduledCharge(
+                data[day]['startTime'],
+                data[day]['duration']
+            )
 
     return data.get('id'), data.get('activated', False), schedule
 
@@ -110,8 +114,8 @@ class ChargeSchedule(object):
 
             if charge_time.spans_midnight:
                 next_day = DAYS[(DAYS.index(day) + 1) % len(DAYS)]
-                tomorrow_charge = self._schedule[next_day]
-                if charge_time.overlaps(tomorrow_charge):
+                tomorrow_charge = self._schedule.get(next_day)
+                if tomorrow_charge and charge_time.overlaps(tomorrow_charge):
                     raise InvalidScheduleException('Charge for {} overlaps charge for {}'.format(day, next_day))
         return True
 
@@ -129,6 +133,9 @@ class ChargeSchedule(object):
         # to make it valid (or else risk it being essentially immutable without gymnastics).
         self._schedule[key] = value
 
+    def __delitem__(self, key):
+        return self._schedule.__delitem__(key)
+
     def items(self):
         return self._schedule.items()
 
@@ -143,8 +150,8 @@ class ChargeSchedule(object):
             'id': self.id,
             'activated': self.activated
         }
-        for day in DAYS:
-            result[day] = self._schedule[day].for_json()
+        for day, schedule in self._schedule.items():
+            result[day] = schedule.for_json()
         return result
 
 
diff --git a/src/pyze/cli/schedule.py b/src/pyze/cli/schedule.py
index f22ddad..211135f 100644
--- a/src/pyze/cli/schedule.py
+++ b/src/pyze/cli/schedule.py
@@ -91,6 +91,7 @@ def print_schedule(s, use_utc):
             headers=['Day', 'Start time', 'End time', 'Duration']
         )
     )
+    print()
 
 
 def format_schedule(s, use_utc):


Test patch:
diff --git a/src/pyze/api/__tests__/test_schedule.py b/src/pyze/api/__tests__/test_schedule.py
index b4bd8ac..ec16671 100644
--- a/src/pyze/api/__tests__/test_schedule.py
+++ b/src/pyze/api/__tests__/test_schedule.py
@@ -231,3 +231,9 @@ class TestChargeSchedule():
         expected = INITIAL_SCHEDULE.copy()
         expected['id'] = None
         assert cs.for_json() == expected
+
+        # New API allows days to have no scheduled charges
+        # see https://github.com/jamesremuscat/pyze/issues/46
+        del cs['monday']
+        del expected['monday']
+        assert cs.for_json() == expected
diff --git a/src/pyze/cli/__tests__/test_cli_schedule.py b/src/pyze/cli/__tests__/test_cli_schedule.py
new file mode 100644
index 0000000..f513e0f
--- /dev/null
+++ b/src/pyze/cli/__tests__/test_cli_schedule.py
@@ -0,0 +1,71 @@
+from collections import namedtuple
+from pyze.api.schedule import ChargeSchedules
+from pyze.cli.schedule import show
+
+
+def test_show(capsys):
+    valid_gappy_schedules = {
+        "mode": "always",
+        "schedules": [
+            {
+                "id": 1,
+                "activated": True,
+                "monday": {
+                    "startTime": "T23:30Z",
+                    "duration": 60
+                },
+                "thursday": {
+                    "startTime": "T01:00Z",
+                    "duration": 120
+                }
+            },
+            {
+                "id": 2,
+                "activated": False
+            },
+            {
+                "id": 3,
+                "activated": False
+            },
+            {
+                "id": 4,
+                "activated": False
+            },
+            {
+                "id": 5,
+                "activated": False
+            }
+        ]
+    }
+
+    cs = ChargeSchedules(valid_gappy_schedules)
+    show(cs, None, namedtuple('parsed_args', ['utc'])(False))
+
+    output = capsys.readouterr()
+
+    expected_out = '''
+Schedule ID: 1 [Active]
+Day       Start time    End time    Duration
+--------  ------------  ----------  ----------
+Monday    23:30         00:30+      1:00:00
+Thursday  01:00         03:00       2:00:00
+
+Schedule ID: 2
+Day    Start time    End time    Duration
+-----  ------------  ----------  ----------
+
+Schedule ID: 3
+Day    Start time    End time    Duration
+-----  ------------  ----------  ----------
+
+Schedule ID: 4
+Day    Start time    End time    Duration
+-----  ------------  ----------  ----------
+
+Schedule ID: 5
+Day    Start time    End time    Duration
+-----  ------------  ----------  ----------
+
+'''.strip()
+
+    assert output.out.strip() == expected_out