Repository: pimutils/khal
Pull request #850 (2019-03-25 10:22:20)

Fix/823


Patch:
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 0f0d3b7..147b83e 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -15,7 +15,7 @@ not released yet
 
 * NEW DEPENDENCY added click_log  >= 0.2.0
 * NEW DEPENDENCY for Python 3.4: typing
-* UPDATED DEPENDENCY icalendar>=3.11.7
+* UPDATED DEPENDENCY icalendar>=4.03
 * DROPPED support for Python 3.3
 * vdirsyncer is still a test dependency (and always has been)
 
diff --git a/khal/cli.py b/khal/cli.py
index 0ae2b13..fa1686d 100644
--- a/khal/cli.py
+++ b/khal/cli.py
@@ -335,7 +335,7 @@ def _get_cli():
     @click.option('--location', '-l',
                   help=('The location of the new event.'))
     @click.option('--categories', '-g',
-                  help=('The categories of the new event.'))
+                  help=('The categories of the new event, comma separated.'))
     @click.option('--repeat', '-r',
                   help=('Repeat event: daily, weekly, monthly or yearly.'))
     @click.option('--until', '-u',
@@ -357,10 +357,9 @@ def _get_cli():
         everything behind them is taken as the event's description.
         '''
         if not info and not interactive:
-                raise click.BadParameter(
-                    'no details provided, '
-                    'did you mean to use --interactive/-i?'
-                )
+            raise click.BadParameter(
+                'no details provided, did you mean to use --interactive/-i?'
+            )
 
         calendar = calendar or ctx.obj['conf']['default']['default_calendar']
         if calendar is None:
diff --git a/khal/controllers.py b/khal/controllers.py
index 9d2d79b..e774d6c 100644
--- a/khal/controllers.py
+++ b/khal/controllers.py
@@ -187,9 +187,9 @@ def get_events_between(
         # to understand what's going on here this way
         if notstarted:
             if event.allday and event.start < original_start.date():
-                    continue
+                continue
             elif not event.allday and event.start_local < original_start:
-                    continue
+                continue
         if seen is not None and event.uid in seen:
             continue
 
@@ -355,6 +355,8 @@ def new_from_args(collection, calendar_name, conf, dtstart=None, dtend=None,
                   categories=None, repeat=None, until=None, alarms=None,
                   timezone=None, format=None, env=None):
     """Create a new event from arguments and add to vdirs"""
+    if isinstance(categories, str):
+        categories = list([category.strip() for category in categories.split(',')])
     try:
         event = utils.new_event(
             locale=conf['locale'], location=location, categories=categories,
@@ -495,7 +497,10 @@ def edit_event(event, collection, locale, allow_quit=False, width=80):
             value = prompt(question, default)
             if allow_none and value == "None":
                 value = ""
-            getattr(event, "update_" + attr)(value)
+            if attr == 'categories':
+                getattr(event, "update_" + attr)(list([cat.strip() for cat in value.split(',')]))
+            else:
+                getattr(event, "update_" + attr)(value)
             edited = True
 
         if edited:
@@ -515,9 +520,9 @@ def edit(collection, search_string, locale, format=None, allow_past=False, conf=
     for event in events:
         if not allow_past:
             if event.allday and event.end < now.date():
-                    continue
+                continue
             elif not event.allday and event.end_local < now:
-                    continue
+                continue
         event_text = textwrap.wrap(event.format(format, relative_to=now), term_width)
         echo(''.join(event_text))
         if not edit_event(event, collection, locale, allow_quit=True, width=term_width):
diff --git a/khal/khalendar/event.py b/khal/khalendar/event.py
index 5c006c5..ad76c58 100644
--- a/khal/khalendar/event.py
+++ b/khal/khalendar/event.py
@@ -423,13 +423,16 @@ class Event(object):
 
     @property
     def categories(self):
-        return self._vevents[self.ref].get('CATEGORIES', '')
+        try:
+            return self._vevents[self.ref].get('CATEGORIES', '').to_ical().decode('utf-8')
+        except AttributeError:
+            return ''
 
     def update_categories(self, categories):
-        if categories.strip():
-            self._vevents[self.ref]['CATEGORIES'] = categories
-        else:
-            self._vevents[self.ref].pop('CATEGORIES', False)
+        assert isinstance(categories, list)
+        self._vevents[self.ref].pop('CATEGORIES', False)
+        if categories:
+            self._vevents[self.ref].add('CATEGORIES', categories)
 
     @property
     def description(self):
diff --git a/khal/parse_datetime.py b/khal/parse_datetime.py
index f6e0ae7..5252c5d 100644
--- a/khal/parse_datetime.py
+++ b/khal/parse_datetime.py
@@ -358,7 +358,7 @@ def guessrangefstr(daterange, locale, adjust_reasonably=False,
                 else:
                     end = start + default_timedelta_datetime
             elif end.lower() == 'eod':
-                    end = dt.datetime.combine(start.date(), dt.time.max)
+                end = dt.datetime.combine(start.date(), dt.time.max)
             elif end.lower() == 'week':
                 start -= dt.timedelta(days=(start.weekday() - locale['firstweekday']))
                 end = start + dt.timedelta(days=8)
diff --git a/khal/settings/utils.py b/khal/settings/utils.py
index 5962b53..ca03794 100644
--- a/khal/settings/utils.py
+++ b/khal/settings/utils.py
@@ -153,7 +153,7 @@ def get_color_from_vdir(path):
         color = Vdir(path, '.ics').get_meta('color')
     except CollectionNotFoundError:
         color = None
-    if color is None or color is '':
+    if color is None or color == '':
         logger.debug('Found no or empty file `color` in {}'.format(path))
         return None
     color = color.strip()
diff --git a/khal/ui/calendarwidget.py b/khal/ui/calendarwidget.py
index 1ebe94f..c36db42 100644
--- a/khal/ui/calendarwidget.py
+++ b/khal/ui/calendarwidget.py
@@ -312,9 +312,9 @@ class CListBox(urwid.ListBox):
 
     def keypress(self, size, key):
         if key in self.keybindings['mark'] + ['esc'] and self._marked:
-                self._unmark_all()
-                self._marked = False
-                return
+            self._unmark_all()
+            self._marked = False
+            return
         if key in self.keybindings['mark']:
             self._marked = {'date': self.body.focus_date,
                             'pos': (self.focus_position, self.focus.focus_col)}
diff --git a/khal/ui/editor.py b/khal/ui/editor.py
index 94cadca..a168818 100644
--- a/khal/ui/editor.py
+++ b/khal/ui/editor.py
@@ -433,7 +433,7 @@ class EventEditor(urwid.WidgetWrap):
         self.event.update_summary(get_wrapped_text(self.summary))
         self.event.update_description(get_wrapped_text(self.description))
         self.event.update_location(get_wrapped_text(self.location))
-        self.event.update_categories(get_wrapped_text(self.categories))
+        self.event.update_categories(get_wrapped_text(self.categories).split(','))
 
         if self.startendeditor.changed:
             self.event.update_start_end(
diff --git a/khal/utils.py b/khal/utils.py
index a26048d..6e6013b 100644
--- a/khal/utils.py
+++ b/khal/utils.py
@@ -655,7 +655,7 @@ def cal_from_ics(ics):
     except ValueError as error:
         if (len(error.args) > 0 and isinstance(error.args[0], str) and
                 error.args[0].startswith('Offset must be less than 24 hours')):
-            logger.warn(
+            logger.warning(
                 'Invalid timezone offset encountered, '
                 'timezone information may be wrong: ' + str(error.args[0])
             )
diff --git a/setup.py b/setup.py
index 309f133..b3985ff 100755
--- a/setup.py
+++ b/setup.py
@@ -13,7 +13,7 @@ if sys.version_info < (3, 4):
 requirements = [
     'click>=3.2',
     'click_log>=0.2.0',
-    'icalendar>=3.11.7',
+    'icalendar>=4.0.3',
     'urwid',
     'pyxdg',
     'pytz',


Test patch:
diff --git a/tests/cal_display_test.py b/tests/cal_display_test.py
index e3b247d..062c70c 100644
--- a/tests/cal_display_test.py
+++ b/tests/cal_display_test.py
@@ -45,9 +45,9 @@ class testCollection():
 def test_get_calendar_color():
 
     exampleCollection = testCollection()
-    exampleCollection.addCalendar('testCalendar1', 'dark red',    20)
+    exampleCollection.addCalendar('testCalendar1', 'dark red', 20)
     exampleCollection.addCalendar('testCalendar2', 'light green', 10)
-    exampleCollection.addCalendar('testCalendar3', '',            10)
+    exampleCollection.addCalendar('testCalendar3', '', 10)
 
     assert get_calendar_color('testCalendar1', 'light blue', exampleCollection) == 'dark red'
     assert get_calendar_color('testCalendar2', 'light blue', exampleCollection) == 'light green'
@@ -62,7 +62,7 @@ def test_get_color_list():
 
     # test different priorities
     exampleCollection1 = testCollection()
-    exampleCollection1.addCalendar('testCalendar1', 'dark red',    20)
+    exampleCollection1.addCalendar('testCalendar1', 'dark red', 20)
     exampleCollection1.addCalendar('testCalendar2', 'light green', 10)
 
     testList1 = get_color_list(exampleCalendarList, 'light_blue', exampleCollection1)
@@ -71,7 +71,7 @@ def test_get_color_list():
 
     # test same priorities
     exampleCollection2 = testCollection()
-    exampleCollection2.addCalendar('testCalendar1', 'dark red',    20)
+    exampleCollection2.addCalendar('testCalendar1', 'dark red', 20)
     exampleCollection2.addCalendar('testCalendar2', 'light green', 20)
 
     testList2 = get_color_list(exampleCalendarList, 'light_blue', exampleCollection2)
@@ -81,16 +81,16 @@ def test_get_color_list():
 
     # test duplicated colors
     exampleCollection3 = testCollection()
-    exampleCollection3.addCalendar('testCalendar1', 'dark red',    20)
-    exampleCollection3.addCalendar('testCalendar2', 'dark red',    20)
+    exampleCollection3.addCalendar('testCalendar1', 'dark red', 20)
+    exampleCollection3.addCalendar('testCalendar2', 'dark red', 20)
 
     testList3 = get_color_list(exampleCalendarList, 'light_blue', exampleCollection3)
     assert len(testList3) == 1
 
     # test indexing operator (required by str_highlight_day())
     exampleCollection4 = testCollection()
-    exampleCollection4.addCalendar('testCalendar1', 'dark red',    20)
-    exampleCollection4.addCalendar('testCalendar2', 'dark red',    20)
+    exampleCollection4.addCalendar('testCalendar1', 'dark red', 20)
+    exampleCollection4.addCalendar('testCalendar2', 'dark red', 20)
 
     testList3 = get_color_list(exampleCalendarList, 'light_blue', exampleCollection4)
     assert testList3[0] == 'dark red'
diff --git a/tests/event_test.py b/tests/event_test.py
index d385272..2bf2d6e 100644
--- a/tests/event_test.py
+++ b/tests/event_test.py
@@ -52,7 +52,7 @@ def test_update_simple():
     event.update_summary('A not so simple Event')
     event.update_description('Everything has changed')
     event.update_location('anywhere')
-    event.update_categories('meeting')
+    event.update_categories(['meeting'])
     assert normalize_component(event.raw) == normalize_component(event_updated.raw)
 
 
@@ -92,7 +92,7 @@ def test_remove_existing_description_if_set_to_empty():
 def test_update_remove_categories():
     event = Event.fromString(_get_text('event_dt_simple_updated'), **EVENT_KWARGS)
     event_nocat = Event.fromString(_get_text('event_dt_simple_nocat'), **EVENT_KWARGS)
-    event.update_categories('    ')
+    event.update_categories([])
     assert normalize_component(event.raw) == normalize_component(event_nocat.raw)
 
 
diff --git a/tests/khalendar_test.py b/tests/khalendar_test.py
index 48016f5..b671f56 100644
--- a/tests/khalendar_test.py
+++ b/tests/khalendar_test.py
@@ -305,26 +305,26 @@ class TestCollection(object):
             '{start} {end} {title}', dt.date.today()) == '07.07. 08:30 07.07. 12:00 Arbeit\x1b[0m'
 
     def test_delete_two_events(self, coll_vdirs, sleep_time):
-            """testing if we can delete any of two events in two different
-            calendars with the same filename"""
-            coll, vdirs = coll_vdirs
-            event1 = Event.fromString(
-                _get_text('event_dt_simple'), calendar=cal1, locale=LOCALE_BERLIN)
-            event2 = Event.fromString(
-                _get_text('event_dt_simple'), calendar=cal2, locale=LOCALE_BERLIN)
-            coll.new(event1, cal1)
-            sleep(sleep_time)  # make sure the etags are different
-            coll.new(event2, cal2)
-            etag1 = list(vdirs[cal1].list())[0][1]
-            etag2 = list(vdirs[cal2].list())[0][1]
-            events = list(coll.get_localized(self.astart_berlin, self.aend_berlin))
-            assert len(events) == 2
-            assert events[0].calendar != events[1].calendar
-            for event in events:
-                if event.calendar == cal1:
-                    assert event.etag == etag1
-                if event.calendar == cal2:
-                    assert event.etag == etag2
+        """testing if we can delete any of two events in two different
+        calendars with the same filename"""
+        coll, vdirs = coll_vdirs
+        event1 = Event.fromString(
+            _get_text('event_dt_simple'), calendar=cal1, locale=LOCALE_BERLIN)
+        event2 = Event.fromString(
+            _get_text('event_dt_simple'), calendar=cal2, locale=LOCALE_BERLIN)
+        coll.new(event1, cal1)
+        sleep(sleep_time)  # make sure the etags are different
+        coll.new(event2, cal2)
+        etag1 = list(vdirs[cal1].list())[0][1]
+        etag2 = list(vdirs[cal2].list())[0][1]
+        events = list(coll.get_localized(self.astart_berlin, self.aend_berlin))
+        assert len(events) == 2
+        assert events[0].calendar != events[1].calendar
+        for event in events:
+            if event.calendar == cal1:
+                assert event.etag == etag1
+            if event.calendar == cal2:
+                assert event.etag == etag2
 
     def test_invalid_timezones(self, coll_vdirs):
         """testing if we can delete any of two events in two different
diff --git a/tests/parse_datetime_test.py b/tests/parse_datetime_test.py
index 7f21aee..741399b 100644
--- a/tests/parse_datetime_test.py
+++ b/tests/parse_datetime_test.py
@@ -191,11 +191,11 @@ class TestGuessTimedeltafstr:
 
     def test_garbage(self):
         with pytest.raises(ValueError):
-                guesstimedeltafstr('10mbar')
+            guesstimedeltafstr('10mbar')
 
     def test_moregarbage(self):
         with pytest.raises(ValueError):
-                guesstimedeltafstr('foo10m')
+            guesstimedeltafstr('foo10m')
 
     def test_same(self):
         assert dt.timedelta(minutes=20) == \
@@ -206,16 +206,16 @@ class TestGuessRangefstr:
 
     @freeze_time('2016-9-19')
     def test_today(self):
-            assert (dt.datetime(2016, 9, 19, 13), dt.datetime(2016, 9, 19, 14), False) == \
-                guessrangefstr('13:00 14:00', locale=LOCALE_BERLIN)
-            assert (dt.datetime(2016, 9, 19), dt.datetime(2016, 9, 21), True) == \
-                guessrangefstr('today tomorrow', LOCALE_BERLIN)
+        assert (dt.datetime(2016, 9, 19, 13), dt.datetime(2016, 9, 19, 14), False) == \
+            guessrangefstr('13:00 14:00', locale=LOCALE_BERLIN)
+        assert (dt.datetime(2016, 9, 19), dt.datetime(2016, 9, 21), True) == \
+            guessrangefstr('today tomorrow', LOCALE_BERLIN)
 
     @freeze_time('2016-9-19 16:34')
     def test_tomorrow(self):
         # XXX remove this funtionality, we shouldn't support this anyway
-            assert (dt.datetime(2016, 9, 19), dt.datetime(2016, 9, 21, 16), True) == \
-                guessrangefstr('today tomorrow 16:00', locale=LOCALE_BERLIN)
+        assert (dt.datetime(2016, 9, 19), dt.datetime(2016, 9, 21, 16), True) == \
+            guessrangefstr('today tomorrow 16:00', locale=LOCALE_BERLIN)
 
     @freeze_time('2016-9-19 13:34')
     def test_time_tomorrow(self):
@@ -554,6 +554,6 @@ def test_description_and_location_and_categories():
         event = _construct_event(data_list.split(),
                                  description='please describe the event',
                                  location='in the office',
-                                 categories='boring meeting',
+                                 categories=['boring meeting'],
                                  locale=LOCALE_BERLIN)
         assert _replace_uid(event).to_ical() == vevent