Skip to content

Commit ea00567

Browse files
add alarms-list output formats (#1438)
Adds --format and --json to list alarms. Semi-fixes #148, actual alarm implementation can be done externally.
1 parent 8c925c7 commit ea00567

5 files changed

Lines changed: 69 additions & 2 deletions

File tree

doc/source/usage.rst

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,9 @@ Several options are common to almost all of :program:`khal`'s commands
115115
alarm-symbol
116116
An alarm symbol (alarm clock) if the event has at least one alarm.
117117

118+
alarms-list
119+
A comma-separated list of alarms for the event (e.g., `alarm1@-15m, getready@-1h`).
120+
118121
location
119122
The event location.
120123

@@ -222,7 +225,7 @@ Several options are common to almost all of :program:`khal`'s commands
222225
end-date-long, end-time, start-full, start-long-full,
223226
start-date-full, start-date-long-full, start-time-full,
224227
end-full, end-long-full, end-date-full, end-date-long-full,
225-
end-time-full, repeat-symbol, location, calendar,
228+
end-time-full, repeat-symbol, alarms-list, location, calendar,
226229
calendar-color, start-style, to-style, end-style,
227230
start-end-time-style, end-necessary, end-necessary-long,
228231
status, cancelled, organizer, url, duration, duration-full,

khal/khalendar/event.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import logging
2727
import os
2828
from collections.abc import Callable
29+
from typing import Any
2930

3031
import icalendar
3132
import icalendar.cal
@@ -612,7 +613,7 @@ def attributes(
612613
"""
613614
env = env or {}
614615

615-
attributes = {}
616+
attributes: dict[str, Any] = {}
616617
if isinstance(relative_to, tuple):
617618
relative_to_start, relative_to_end = relative_to
618619
else:
@@ -734,6 +735,14 @@ def attributes(
734735
attributes["repeat-symbol"] = self._recur_str
735736
attributes["repeat-pattern"] = self.recurpattern
736737
attributes["alarm-symbol"] = self._alarm_str
738+
attributes["alarms-list"] = [
739+
{
740+
"delta": alarm[0].total_seconds(),
741+
"description": str(alarm[1]),
742+
"delta-formatted": timedelta2str(alarm[0]),
743+
}
744+
for alarm in self.alarms
745+
]
737746
attributes["status-symbol"] = self._status_str
738747
attributes["partstat-symbol"] = self._partstat_str
739748
attributes["title"] = self.summary

khal/utils.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,12 @@ def fmt(rows):
197197
if "calendar-color" in row:
198198
row["calendar-color"] = get_color(row["calendar-color"])
199199

200+
if "alarms-list" in row and isinstance(row["alarms-list"], list):
201+
row["alarms-list"] = ", ".join(
202+
alarm["description"] + "@" + alarm["delta-formatted"]
203+
for alarm in row["alarms-list"]
204+
)
205+
200206
s = format_string.format(**row)
201207

202208
if colors:
@@ -245,6 +251,7 @@ def fmt(rows):
245251
"end-necessary-long",
246252
"repeat-symbol",
247253
"repeat-pattern",
254+
"alarms-list",
248255
"title",
249256
"organizer",
250257
"description",

tests/cli_test.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,32 @@ def test_list_json(runner):
527527
assert result.output.startswith(expected)
528528

529529

530+
def test_list_alarms(runner):
531+
runner = runner(days=2)
532+
now = dt.datetime.now().strftime("%d.%m.%Y")
533+
runner.invoke(main_khal, f"new {now} 18:00 myevent --alarms -15m,1h".split())
534+
args = ["list", "--format", "{alarms-list}", "--day-format", ""]
535+
result = runner.invoke(main_khal, args)
536+
assert not result.exception
537+
assert result.output.strip() == "@15m, @-1h"
538+
539+
540+
def test_list_alarms_json(runner):
541+
runner = runner()
542+
now = dt.datetime.now().strftime("%d.%m.%Y")
543+
runner.invoke(main_khal, f"new {now} 18:00 myevent --alarms 15m,1h".split())
544+
args = ["list", "--json", "alarms-list"]
545+
result = runner.invoke(main_khal, args)
546+
expected = '[{"alarms-list": [\
547+
{"delta": -900.0, "description": "", "delta-formatted": "-15m"}, \
548+
{"delta": -3600.0, "description": "", "delta-formatted": "-1h"}\
549+
]}]'
550+
print(result.output)
551+
print(expected)
552+
assert not result.exception
553+
assert result.output.startswith(expected)
554+
555+
530556
def test_search(runner):
531557
runner = runner(days=2)
532558
now = dt.datetime.now().strftime("%d.%m.%Y")

tests/event_test.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -596,6 +596,28 @@ def test_event_alarm():
596596
assert event.alarms == [(dt.timedelta(-1, 82800), vText("new event"))]
597597

598598

599+
def test_event_alarm_list():
600+
"""test the content of `alarms-list` attribute"""
601+
event = Event.fromString(_get_text("event_dt_simple"), **EVENT_KWARGS)
602+
assert event.alarms == []
603+
event.update_alarms(
604+
[(dt.timedelta(minutes=30), "alarm 1"), (-dt.timedelta(hours=1, minutes=30), "alarm 2")]
605+
)
606+
attributes = event.attributes(dt.date.today())
607+
assert attributes["alarms-list"] == [
608+
{"delta": 1800.0, "description": "alarm 1", "delta-formatted": "30m"},
609+
{"delta": -5400.0, "description": "alarm 2", "delta-formatted": "-1h -30m"},
610+
]
611+
612+
613+
def test_event_no_alarms_list():
614+
"""test that `alarms-list` is empty for an event with no alarms"""
615+
event = Event.fromString(_get_text("event_dt_simple"), **EVENT_KWARGS)
616+
assert event.alarms == []
617+
attributes = event.attributes(dt.date.today())
618+
assert attributes["alarms-list"] == []
619+
620+
599621
def test_event_attendees():
600622
event = Event.fromString(_get_text("event_dt_simple"), **EVENT_KWARGS)
601623
assert event.attendees == ""

0 commit comments

Comments
 (0)