-
Notifications
You must be signed in to change notification settings - Fork 0
/
Converter3.py
188 lines (146 loc) · 6.74 KB
/
Converter3.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
"""
This module is taken from https://github.com/n8henrie/icsConverter
"""
import csv
from icalendar import Calendar, Event, LocalTimezone
from datetime import datetime, timedelta
from random import randint
import sys
import logging
logging.basicConfig(level=logging.WARNING)
logger = logging.getLogger(__name__)
class HeadersError(Exception):
pass
class DateTimeError(Exception):
pass
def check_headers(headers):
"""Makes sure that all the headers are exactly
correct so that they'll be recognized as the
necessary keys."""
valid_keys = ['End Date', 'Description',
'All Day Event', 'Start Time', 'Private',
'End Time', 'Location', 'Start Date', 'Subject']
if (set(headers) != set(valid_keys)
or len(headers) != len(valid_keys)):
for header in headers:
if header not in valid_keys:
if header == '':
header = '"" (<- an empty column)'
logger.error('Invalid header: {}'.format(header))
raise HeadersError('Something isn\'t right with the headers.')
elif len(headers) < len(valid_keys):
logger.error('Missing headers: {}'.format(list(set(valid_keys) - set(headers))))
raise HeadersError('Something isn\'t right with the headers.')
elif len(headers) > len(valid_keys):
duplicate = list(set([i for i in headers if headers.count(i) > 1]))
logger.error('Extra headers: {}'.format(duplicate))
raise HeadersError('Something isn\'t right with the headers.')
else:
return 'headers passed'
def clean_spaces(csv_dict):
'''Cleans trailing spaces from the dictionary
values, which can break my datetime patterns.'''
clean_row = {}
for row in csv_dict:
for k, v in row.items():
if v:
clean_row.update({k: v.strip()})
else:
clean_row.update({k: None})
yield clean_row
def check_dates_and_times(
start_date=None, start_time=None,
end_date=None, end_time=None, all_day=None, subject=None
):
'''Checks the dates and times to make sure everything is kosher.'''
logger.debug('Date checker started.')
# must have a start date, no matter what.
if start_date in ['', None]:
logger.error('Missing a start date')
raise DateTimeError('Missing a start date')
for date in [start_date, end_date]:
if date not in ['', None]:
try:
datetime.strptime(date, '%m/%d/%Y')
except:
logger.error('Problem with date formatting. Date: {}'.format(date))
raise DateTimeError('Something isn\'t right with the dates.')
for time in [start_time, end_time]:
if time not in ['', None]:
try:
time = time.replace(' ', '')
if time[-2:].lower() in ['am', 'pm']:
datetime.strptime(time, '%I:%M%p')
else:
datetime.strptime(time, '%H:%M')
except:
logger.error('Problem with time formatting. Time: {}'.format(time))
raise DateTimeError('Something isn\'t right with the times.')
if all_day == None or all_day.lower() != 'true':
if not (start_time and end_time):
logger.error('Missing a required time field in a non-all_day event on date: {}.'.format(start_date))
raise DateTimeError('Missing a required time field in a non-all_day event.')
logger.debug('Date checker ended.')
return True
def convert(infile=None):
reader = list(csv.DictReader(open(infile, 'U'), skipinitialspace=True))
cal = Calendar()
cal.add('prodid', 'https://github.com/kush5683')
cal.add('version', '1.0')
# Write the clean list of dictionaries to events.
rownum = 0
# try:
for row in reader:
event = Event()
event.add('summary', row['Subject'])
try:
check_dates_and_times(
start_date=row.get('Start Date'),
start_time=row.get('Start Time'),
end_date=row.get('End Date'),
end_time=row.get('End Time'),
all_day=row.get('All Day Event'),
subject=row.get('Subject')
)
except DateTimeError as e:
sys.exit(e)
# If marked as an "all day event," ignore times.
# If start and end date are the same
# or if end date is blank default to a single 24-hour event.
if row.get('All Day Event') != None and row['All Day Event'].lower() == 'true':
# All-day events will not be marked as 'busy'
event.add('transp', 'TRANSPARENT')
event.add('dtstart', datetime.strptime(row['Start Date'], '%m/%d/%Y').date())
if row.get('End Date') in ['', None]:
event.add('dtend', (datetime.strptime(row['Start Date'], '%m/%d/%Y') + timedelta(days=1)).date())
else:
event.add('dtend', (datetime.strptime(row['End Date'], '%m/%d/%Y') + timedelta(days=1)).date())
# Continue processing events not marked as "all day" events.
else:
# Events with times should be 'busy' by default
event.add('transp', 'OPAQUE')
# Get rid of spaces
# Note: Must have both start and end times if not all_day, already checked
row['Start Time'] = row['Start Time'].replace(' ', '')
row['End Time'] = row['End Time'].replace(' ', '')
# Allow either 24 hour time or 12 hour + am/pm
if row['Start Time'][-2:].lower() in ['am', 'pm']:
event.add('dtstart', datetime.strptime(row['Start Date'] + row['Start Time'], '%m/%d/%Y%I:%M%p'))
else:
event.add('dtstart', datetime.strptime(row['Start Date'] + row['Start Time'], '%m/%d/%Y%H:%M'))
# Allow blank end dates (assume same day)
if row.get('End Date') in ['', None]:
row['End Date'] = row['Start Date']
if row['End Time'][-2:].lower() in ['am', 'pm']:
event.add('dtend', datetime.strptime(row['End Date'] + row['End Time'], '%m/%d/%Y%I:%M%p'))
else:
event.add('dtend', datetime.strptime(row['End Date'] + row['End Time'], '%m/%d/%Y%H:%M'))
if row.get('Description'):
event.add('description', row['Description'])
if row.get('Location'):
event.add('location', row['Location'])
event.add('dtstamp', datetime.replace(datetime.now(), tzinfo=LocalTimezone()))
event['uid'] = str(randint(1, 10 ** 30)) + datetime.now().strftime('%Y%m%dT%H%M%S') + '___n8henrie.com'
cal.add_component(event)
rownum += 1
return cal.to_ical()