Skip to content
Open
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
5 changes: 4 additions & 1 deletion doc/source/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,9 @@ Several options are common to almost all of :program:`khal`'s commands
alarm-symbol
An alarm symbol (alarm clock) if the event has at least one alarm.

alarms-list
A comma-separated list of alarms for the event (e.g., `alarm1@-15m, getready@-1h`).

location
The event location.

Expand Down Expand Up @@ -222,7 +225,7 @@ Several options are common to almost all of :program:`khal`'s commands
end-date-long, end-time, start-full, start-long-full,
start-date-full, start-date-long-full, start-time-full,
end-full, end-long-full, end-date-full, end-date-long-full,
end-time-full, repeat-symbol, location, calendar,
end-time-full, repeat-symbol, alarms-list, location, calendar,
calendar-color, start-style, to-style, end-style,
start-end-time-style, end-necessary, end-necessary-long,
status, cancelled, organizer, url, duration, duration-full,
Expand Down
12 changes: 10 additions & 2 deletions khal/khalendar/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
import datetime as dt
import logging
import os
from typing import Callable, Optional, Union
from typing import Any, Callable, Optional, Union

import icalendar
import icalendar.cal
Expand Down Expand Up @@ -603,7 +603,7 @@ def attributes(
"""
env = env or {}

attributes = {}
attributes: dict[str, Any] = {}
if isinstance(relative_to, tuple):
relative_to_start, relative_to_end = relative_to
else:
Expand Down Expand Up @@ -722,6 +722,14 @@ def attributes(
attributes["repeat-symbol"] = self._recur_str
attributes["repeat-pattern"] = self.recurpattern
attributes["alarm-symbol"] = self._alarm_str
attributes["alarms-list"] = [
{
"delta": alarm[0].total_seconds(),
"description": str(alarm[1]),
"delta-formatted": timedelta2str(alarm[0])
}
for alarm in self.alarms
]
attributes["status-symbol"] = self._status_str
attributes["partstat-symbol"] = self._partstat_str
attributes["title"] = self.summary
Expand Down
7 changes: 7 additions & 0 deletions khal/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,12 @@ def fmt(rows):
if 'calendar-color' in row:
row['calendar-color'] = get_color(row['calendar-color'])

if 'alarms-list' in row and isinstance(row['alarms-list'], list):
row['alarms-list'] = ", ".join(
alarm['description']+"@"+alarm['delta-formatted']
for alarm in row['alarms-list']
)

s = format_string.format(**row)

if colors:
Expand All @@ -220,6 +226,7 @@ def fmt(rows):
'end-date-full', 'end-date-long-full', 'end-time-full', 'duration-full',
'start-style', 'end-style', 'to-style', 'start-end-time-style',
'end-necessary', 'end-necessary-long', 'repeat-symbol', 'repeat-pattern',
'alarms-list',
'title', 'organizer', 'description', 'location', 'all-day', 'categories',
'uid', 'url', 'calendar', 'calendar-color', 'status', 'cancelled']

Expand Down
28 changes: 28 additions & 0 deletions tests/cli_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,34 @@ def test_list_json(runner):
assert result.output.startswith(expected)


def test_list_alarms(runner):
runner = runner(days=2)
now = dt.datetime.now().strftime('%d.%m.%Y')
runner.invoke(
main_khal,
f"new {now} 18:00 myevent --alarms -15m,1h".split())
args = ['list', '--format', '{alarms-list}', '--day-format', '']
result = runner.invoke(main_khal, args)
assert not result.exception
assert result.output.strip() == '@15m, @-1h'


def test_list_alarms_json(runner):
runner = runner()
now = dt.datetime.now().strftime('%d.%m.%Y')
runner.invoke(
main_khal,
f"new {now} 18:00 myevent --alarms 15m,1h".split())
args = ['list', '--json', 'alarms-list']
result = runner.invoke(main_khal, args)
expected = '[{"alarms-list": [\
{"delta": -900.0, "description": "", "delta-formatted": "-15m"},\
{"delta": -3600.0, "description": "", "delta-formatted": "-1h"}\
]}]'
assert not result.exception
assert result.output.startswith(expected)


def test_search(runner):
runner = runner(days=2)
now = dt.datetime.now().strftime('%d.%m.%Y')
Expand Down
21 changes: 21 additions & 0 deletions tests/event_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -538,6 +538,27 @@ def test_event_alarm():
assert event.alarms == [(dt.timedelta(-1, 82800), vText('new event'))]


def test_event_alarm_list():
"""test the content of `alarms-list` attribute"""
event = Event.fromString(_get_text('event_dt_simple'), **EVENT_KWARGS)
assert event.alarms == []
event.update_alarms([(dt.timedelta(minutes=30), 'alarm 1'),
(-dt.timedelta(hours=1, minutes=30), 'alarm 2')])
attributes = event.attributes(dt.date.today())
assert attributes['alarms-list'] == [
{'delta': 1800.0, 'description': 'alarm 1', 'delta-formatted': '30m'},
{'delta': -5400.0, 'description': 'alarm 2', 'delta-formatted': '-1h -30m'}
]


def test_event_no_alarms_list():
"""test that `alarms-list` is empty for an event with no alarms"""
event = Event.fromString(_get_text('event_dt_simple'), **EVENT_KWARGS)
assert event.alarms == []
attributes = event.attributes(dt.date.today())
assert attributes['alarms-list'] == []


def test_event_attendees():
event = Event.fromString(_get_text('event_dt_simple'), **EVENT_KWARGS)
assert event.attendees == ""
Expand Down