From 9c2dfb42318084dead69ffa8d7e51a4fcc6f8c6d Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Sun, 30 Jun 2013 12:19:38 -0400 Subject: [PATCH] entry: Add Entry.process() and .get*() Because we will definitely want a Pythonic API to access entry items. --- pycalendar/entry.py | 97 ++++++++++++++++++++++++++++++++++++++++++++- pycalendar/feed.py | 1 + 2 files changed, 97 insertions(+), 1 deletion(-) diff --git a/pycalendar/entry.py b/pycalendar/entry.py index 692862a..13bcea6 100644 --- a/pycalendar/entry.py +++ b/pycalendar/entry.py @@ -1,11 +1,63 @@ # Copyright +import logging as _logging + +from . import text as _text + + +_LOG = _logging.getLogger(__name__) + + class Entry (object): - """An iCalendar entry (e.g. VEVENT) + r"""An iCalendar entry (e.g. VEVENT) + + Get an entry. + + >>> from .feed import Feed + + >>> import os + >>> root_dir = os.curdir + >>> data_file = os.path.abspath(os.path.join( + ... root_dir, 'test', 'data', 'geohash.ics')) + >>> url = 'file://{}'.format(data_file.replace(os.sep, '/')) + + >>> feed = Feed(url=url) + >>> feed.fetch() + >>> entry = feed.pop() + + Investigate the entry. + + >>> print(entry) + BEGIN:VEVENT + UID:2013-06-30@geohash.invalid + DTSTAMP:2013-06-30T00:00:00Z + DTSTART;VALUE=DATE:20130630 + DTEND;VALUE=DATE:20130701 + SUMMARY:XKCD geohashing\, Boston graticule + URL:http://xkcd.com/426/ + LOCATION:Snow Hill\, Dover\, Massachusetts + GEO:42.226663,-71.28676 + END:VEVENT + + >>> entry.type + 'VEVENT' + >>> entry.content # doctest: +ELLIPSIS + 'BEGIN:VEVENT\r\nUID:...\r\nEND:VEVENT\r\n' + + Use the ``.get*()`` methods to access individual fields. + + >>> entry.get('LOCATION') + 'Snow Hill\\, Dover\\, Massachusetts' + >>> entry.get_text('LOCATION') + 'Snow Hill, Dover, Massachusetts' """ def __init__(self, type, content=None): + super(Entry, self).__init__() self.type = type self.content = content + self.lines = None + if content: + self.process() def __str__(self): if self.content: @@ -15,5 +67,48 @@ class Entry (object): def __repr__(self): return '<{} type:{}>'.format(type(self).__name__, self.type) + def process(self): + self.unfold() + + def unfold(self): + """Unfold wrapped lines + + Following :RFC:`5545`, section 3.1 (Content Lines) + """ + self.lines = [] + semantic_line_chunks = [] + for line in self.content.splitlines(): + lstrip = line.lstrip() + if lstrip != line: + if not semantic_line_chunks: + raise ValueError( + ('whitespace-prefixed line {!r} is not a continuation ' + 'of a previous line').format(line)) + semantic_line_chunks.append(lstrip) + else: + if semantic_line_chunks: + self.lines.append(''.join(semantic_line_chunks)) + semantic_line_chunks = [line] + if semantic_line_chunks: + self.lines.append(''.join(semantic_line_chunks)) + + def get(self, key, **kwargs): + for k in kwargs.keys(): + if k != 'default': + raise TypeError( + 'get() got an unexpected keyword argument {!r}'.format( + k)) + for line in self.lines: + k,value = [x.strip() for x in line.split(':', 1)] + if k == key: + return value + if 'default' in kwargs: + return kwargs['default'] + raise KeyError(key) + + def get_text(self, *args, **kwargs): + value = self.get(*args, **kwargs) + return _text.unescape(value) + def write(self, stream): stream.write(self.content) diff --git a/pycalendar/feed.py b/pycalendar/feed.py index e0d2bc3..150a174 100644 --- a/pycalendar/feed.py +++ b/pycalendar/feed.py @@ -144,6 +144,7 @@ class Feed (set): if len(stack) == 1: entry.content.append('') # trailing blankline entry.content = '\r\n'.join(entry.content) + entry.process() self.add(entry) entry = None -- 2.26.2