1- import yaml
2- import sys
31import os
2+ import sys
43from datetime import datetime , tzinfo
54
6- import ics
75import dateutil
86import dateutil .rrule
7+ import ics
8+ import yaml
99from dateutil .tz import gettz
1010
11-
1211interval_type = {
13- ' seconds' : dateutil .rrule .SECONDLY ,
14- ' minutes' : dateutil .rrule .MINUTELY ,
15- ' hours' : dateutil .rrule .HOURLY ,
16- ' days' : dateutil .rrule .DAILY ,
17- ' weeks' : dateutil .rrule .WEEKLY ,
18- ' months' : dateutil .rrule .MONTHLY ,
19- ' years' : dateutil .rrule .YEARLY
12+ " seconds" : dateutil .rrule .SECONDLY ,
13+ " minutes" : dateutil .rrule .MINUTELY ,
14+ " hours" : dateutil .rrule .HOURLY ,
15+ " days" : dateutil .rrule .DAILY ,
16+ " weeks" : dateutil .rrule .WEEKLY ,
17+ " months" : dateutil .rrule .MONTHLY ,
18+ " years" : dateutil .rrule .YEARLY ,
2019}
2120
2221
23- def event_from_yaml (event_yaml : dict , tz : tzinfo = None ) -> ics .Event :
22+ def event_from_yaml (event_yaml : dict , tz : tzinfo = None ) -> ics .Event :
2423 d = event_yaml
25- repeat = d .pop (' repeat' , None )
24+ repeat = d .pop (" repeat" , None )
2625
2726 # Strip all string values, since they often end on `\n`
2827 for key in d :
@@ -37,42 +36,50 @@ def event_from_yaml(event_yaml: dict, tz: tzinfo=None) -> ics.Event:
3736 event = ics .Event (** d )
3837
3938 # Handle all-day events
40- if not (' duration' in d or ' end' in d ):
39+ if not (" duration" in d or " end" in d ):
4140 event .make_all_day ()
4241
4342 if repeat :
44- interval = repeat [' interval' ]
43+ interval = repeat [" interval" ]
4544
4645 if not len (interval ) == 1 :
47- print ('Error: interval must specify seconds, minutes, hours, days, weeks, months, or years only' , file = sys .stderr )
46+ print (
47+ "Error: interval must specify seconds, minutes, hours, days, weeks, months, or years only" ,
48+ file = sys .stderr ,
49+ )
4850 sys .exit (- 1 )
4951
5052 interval_measure = list (interval .keys ())[0 ]
5153 if interval_measure not in interval_type :
52- print ('Error: expected interval to be specified in seconds, minutes, hours, days, weeks, months, or years only' , file = sys .stderr )
54+ print (
55+ "Error: expected interval to be specified in seconds, minutes, hours, days, weeks, months, or years only" ,
56+ file = sys .stderr ,
57+ )
5358 sys .exit (- 1 )
5459
55- if ' until' not in repeat :
56- print (' Error: must specify end date for repeating events' , file = sys .stderr )
60+ if " until" not in repeat :
61+ print (" Error: must specify end date for repeating events" , file = sys .stderr )
5762 sys .exit (- 1 )
5863
5964 # This causes zero-length events, I guess overriding whatever duration might have been specified.
60- #event.end = d.get('end', None)
65+ # event.end = d.get('end', None)
6166
6267 rrule = dateutil .rrule .rrule (
6368 freq = interval_type [interval_measure ],
64- until = repeat .get (' until' ),
65- dtstart = d [' begin' ]
69+ until = repeat .get (" until" ),
70+ dtstart = d [" begin" ],
6671 )
6772
68- rrule_lines = str (rrule ).split ('\n ' )
69- rrule_dtstart = [line for line in rrule_lines if line .startswith ('DTSTART' )][0 ]
70- rrule_dtstart = rrule_dtstart + 'Z'
71- rrule_rrule = [line for line in rrule_lines if line .startswith ('RRULE' )][0 ]
72- event .extra .append (ics .ContentLine (
73- name = rrule_rrule .split (':' , 1 )[0 ],
74- value = rrule_rrule .split (':' , 1 )[1 ],
75- ))
73+ rrule_lines = str (rrule ).split ("\n " )
74+ rrule_dtstart = [line for line in rrule_lines if line .startswith ("DTSTART" )][0 ]
75+ rrule_dtstart = rrule_dtstart + "Z"
76+ rrule_rrule = [line for line in rrule_lines if line .startswith ("RRULE" )][0 ]
77+ event .extra .append (
78+ ics .ContentLine (
79+ name = rrule_rrule .split (":" , 1 )[0 ],
80+ value = rrule_rrule .split (":" , 1 )[1 ],
81+ )
82+ )
7683
7784 event .dtstamp = datetime .utcnow ().replace (tzinfo = dateutil .tz .UTC )
7885 if tz and event .floating and not event .all_day :
@@ -86,34 +93,34 @@ def events_to_calendar(events: list) -> str:
8693 cal .events .append (event )
8794 return cal
8895
96+
8997def files_to_calendar (files : list ) -> ics .Calendar :
9098 """'main' function: list of files to our result"""
91- all_events = [ ]
92- name = None
99+ all_events = []
93100 for f in files :
94- if hasattr (f , ' read' ):
101+ if hasattr (f , " read" ):
95102 calendar_yaml = yaml .load (f .read (), Loader = yaml .FullLoader )
96103 else :
97- calendar_yaml = yaml .load (open (f , 'r' ), Loader = yaml .FullLoader )
104+ calendar_yaml = yaml .load (open (f , "r" ), Loader = yaml .FullLoader )
98105 tz = None
99- if ' meta' in calendar_yaml :
100- if 'tz' in calendar_yaml [' meta' ]:
101- tz = gettz (calendar_yaml [' meta' ][ 'tz' ])
102- for event in calendar_yaml [' events' ]:
106+ if " meta" in calendar_yaml :
107+ if "tz" in calendar_yaml [" meta" ]:
108+ tz = gettz (calendar_yaml [" meta" ][ "tz" ])
109+ for event in calendar_yaml [" events" ]:
103110 all_events .append (event_from_yaml (event , tz = tz ))
104111 calendar = events_to_calendar (all_events )
105112 return calendar
106113
107114
108- if __name__ == ' __main__' :
115+ if __name__ == " __main__" :
109116 if len (sys .argv ) < 2 :
110- print (' Usage: yaml2ics.py FILE1.yaml FILE2.yaml ...' )
117+ print (" Usage: yaml2ics.py FILE1.yaml FILE2.yaml ..." )
111118 sys .exit (- 1 )
112119
113120 files = sys .argv [1 :]
114121 for f in files :
115122 if not os .path .isfile (f ):
116- print (f' Error: { f } is not a file' , file = sys .stderr )
123+ print (f" Error: { f } is not a file" , file = sys .stderr )
117124 sys .exit (- 1 )
118125
119126 calendar = files_to_calendar (files )
0 commit comments