Refactor construction of meetings list.

Handle undefined values gracefully in the Meeting and
Scheduler definitions. Refactor the Meeting class with improved
initialization and clean up the creation of the meetings
list.

Change-Id: Iad6a712c4b05c8af440c1f89966ae81102bb3e4e
This commit is contained in:
stephane 2015-02-25 16:24:10 -08:00
parent 40f12c0d63
commit affdcfa153
3 changed files with 62 additions and 33 deletions

View File

@ -150,8 +150,7 @@ will be import into Python as a dictionary.
irc: openstack-meeting irc: openstack-meeting
frequency: biweekly-odd frequency: biweekly-odd
* The chair is just a one liner. The might be left empty if there is not a * The chair is just a one liner.
chair.
:: ::

View File

@ -14,6 +14,7 @@ import datetime
import icalendar import icalendar
import logging import logging
import os import os
import os.path
import pytz import pytz
from yaml2ical import meeting from yaml2ical import meeting
@ -99,7 +100,7 @@ def convert_yaml_to_ical(yaml_dir, outputdir=None, outputfile=None):
for m in meetings: for m in meetings:
cal = Yaml2IcalCalendar() cal = Yaml2IcalCalendar()
cal.add_meeting(m) cal.add_meeting(m)
filename = m.filefrom.split('.')[0] + '.ics' filename = os.path.splitext(m.filefrom)[0] + '.ics'
cal.write_to_disk(os.path.join(outputdir, filename)) cal.write_to_disk(os.path.join(outputdir, filename))
# convert meetings into a single ical # convert meetings into a single ical

View File

@ -11,9 +11,12 @@
# under the License. # under the License.
import datetime import datetime
from io import StringIO
import os import os
import os.path
import yaml import yaml
from yaml2ical.recurrence import supported_recurrences from yaml2ical.recurrence import supported_recurrences
@ -25,11 +28,16 @@ class Schedule(object):
self.project = meeting.project self.project = meeting.project
self.filefrom = meeting.filefrom self.filefrom = meeting.filefrom
self.time = datetime.datetime.strptime(sched_yaml['time'], '%H%M') try:
self.day = sched_yaml['day'] self.time = datetime.datetime.strptime(sched_yaml['time'], '%H%M')
self.irc = sched_yaml['irc'] self.day = sched_yaml['day']
self.freq = sched_yaml['frequency'] self.irc = sched_yaml['irc']
self.recurrence = supported_recurrences[sched_yaml['frequency']] self.freq = sched_yaml['frequency']
self.recurrence = supported_recurrences[sched_yaml['frequency']]
except KeyError as e:
print("Invalid YAML meeting schedule definition - missing "
"attribute '{0}'".format(e.args[0]))
raise
def conflicts(self, other): def conflicts(self, other):
"""Checks for conflicting schedules.""" """Checks for conflicting schedules."""
@ -44,20 +52,40 @@ class Schedule(object):
class Meeting(object): class Meeting(object):
"""An OpenStack meeting.""" """An OpenStack meeting."""
def __init__(self, filename, meeting_yaml): def __init__(self, data):
"""Initialize meeting from meeting yaml description.""" """Initialize meeting from meeting yaml description."""
yaml_obj = yaml.safe_load(meeting_yaml) yaml_obj = yaml.safe_load(data)
self.chair = yaml_obj['chair']
self.description = yaml_obj['description'] try:
self.project = yaml_obj['project'] self.chair = yaml_obj['chair']
self.filefrom = os.path.basename(filename) self.description = yaml_obj['description']
self.project = yaml_obj['project']
except KeyError as e:
print("Invalid YAML meeting definition - missing "
"attribute '{0}'".format(e.args[0]))
raise
try:
self.filefrom = os.path.basename(data.name)
except AttributeError:
self.filefrom = "stdin"
self.schedules = [] self.schedules = []
for sch in yaml_obj['schedule']: for sch in yaml_obj['schedule']:
s = Schedule(self, sch) s = Schedule(self, sch)
self.schedules.append(s) self.schedules.append(s)
@classmethod
def fromfile(cls, yaml_file):
f = open(yaml_file, 'r')
return cls(f)
@classmethod
def fromstring(cls, yaml_string):
s = StringIO(yaml_string)
return cls(s)
def load_meetings(yaml_source): def load_meetings(yaml_source):
"""Build YAML object and load meeting data """Build YAML object and load meeting data
@ -66,29 +94,30 @@ def load_meetings(yaml_source):
stream. stream.
:returns: list of meeting objects :returns: list of meeting objects
""" """
meetings_yaml = [] meetings = []
# Determine what the yaml_source is # Determine what the yaml_source is. Files must have .yaml extension
# to be considered valid.
if os.path.isdir(yaml_source): if os.path.isdir(yaml_source):
# TODO(lbragstad): use os.path.walk? for root, dirs, files in os.walk(yaml_source):
for f in os.listdir(yaml_source): for f in files:
# Build the entire file path and append to the list of yaml # Build the entire file path and append to the list of yaml
# meetings # meetings
yaml_file = os.path.join(yaml_source, f) if os.path.splitext(f)[1] == '.yaml':
meetings_yaml.append(yaml_file) yaml_file = os.path.join(root, f)
meetings.append(Meeting.fromfile(yaml_file))
elif (os.path.isfile(yaml_source) and
os.path.splitext(yaml_source)[1] == '.yaml'):
meetings.append(Meeting.fromfile(yaml_source))
elif isinstance(yaml_source, str): elif isinstance(yaml_source, str):
return [Meeting("stdin", yaml_source)] return [Meeting.fromstring(yaml_source)]
else:
if not meetings:
# If we don't have a .yaml file, a directory of .yaml files, or any # If we don't have a .yaml file, a directory of .yaml files, or any
# YAML data fail out here. # YAML data fail out here.
raise ValueError("YAML source isn't a .yaml file, directory " raise ValueError("No .yaml file, directory containing .yaml files, "
"containing .yaml files, or YAML data.") "or YAML data found.")
else:
meetings = [] return meetings
for yaml_file in meetings_yaml:
with open(yaml_file, 'r') as f:
meetings.append(Meeting(yaml_file, f))
return meetings
class MeetingConflictError(Exception): class MeetingConflictError(Exception):