Revision: 155
Author:
cmpi...@gmail.com
Date: Fri Sep 21 12:47:50 2012
Log: For issue #44 ("Add ability to attach images with captions to
entries"), add diary file format support for attachments.
* lib/tk_data.py
(TKJ_TAG_ATTACHMENT, TKJ_TAG_ATTACHMENTS, TKJ_TAG_DATA,
TKJ_TAG_DESC): New tags.
(TKEntries._valid_parents): Update validation rules to accomodate
new tags.
(TKEntryAttachment): New class.
(TKEntry.__init__): Add 'attachments' parameter.
(TKEntry.get_attachments): New function.
(TKDataParser.startElement, TKDataParser.endElement): Add parsing of
new attachments bit.
(TKDataParser._write_entry): Unparse attachments, too.
http://code.google.com/p/thotkeeper/source/detail?r=155
Modified:
/trunk/lib/tk_data.py
=======================================
--- /trunk/lib/tk_data.py Tue Jun 15 10:38:42 2010
+++ /trunk/lib/tk_data.py Fri Sep 21 12:47:50 2012
@@ -10,6 +10,7 @@
#
# Website:
http://www.thotkeeper.org/
+import base64
import os
import shutil
import tempfile
@@ -50,9 +51,25 @@
return MySet()
+class TKEntryAttachment:
+ def __init__(self, description='', content_type=None, data=None):
+ self.description = description
+ self.content_type = content_type
+ self.data = data
+
+ def get_description(self):
+ return self.description
+
+ def get_content_type(self):
+ return self.content_type
+
+ def get_data(self):
+ return self.data
+
class TKEntry:
def __init__(self, author='', subject='', text='',
- year=None, month=None, day=None, id=None, tags=[]):
+ year=None, month=None, day=None, id=None,
+ tags=[], attachments=[]):
self.author = author
self.subject = subject
self.text = text
@@ -61,6 +78,7 @@
self.day = day
self.id = id
self.tags = tags
+ self.attachments = attachments
def get_author(self):
return self.author
@@ -79,6 +97,9 @@
def get_tags(self):
return self.tags
+
+ def get_attachments(self):
+ return self.attachments
class TKEntries:
def __init__(self):
@@ -328,7 +349,7 @@
</entries>
</diary>
- Version 1 (unreleased): Adds an "id" attribute to entries for the
+ Version 1 (ThotKeeker 0.2): Adds an "id" attribute to entries for the
purposes of distinguishing multiple entries for a given day. Adds
an optional <tags> tag to entries, which contains 1 or more <tag>
tags.
@@ -348,10 +369,41 @@
...
</entries>
</diary>
-
+
+ Version 2 (ThotKeeker 0.5): Adds optional elements (the
+ <attachments> tag and its children) for tracking entry attachments
+ -- such as images -- and descriptions thereof.
+
+ <diary version="1">
+ <author global="True/False">CDATA</author>
+ <entries>
+ <entry year="YYYY" month="M" day="D" id="N">
+ <author>CDATA</author>
+ <subject>CDATA</subject>
+ <tags>
+ <tag>CDATA</tag>
+ ...
+ </tags>
+ <text>CDATA</text>
+ <attachments>
+ <attachment content-type="T">>
+ <description>CDATA</description>
+ <data>base64(DATA)</data>
+ </attachment>
+ ...
+ </attachments>
+ </entry>
+ ...
+ </entries>
+ </diary>
+
"""
+ TKJ_TAG_ATTACHMENT = 'attachment'
+ TKJ_TAG_ATTACHMENTS = 'attachments'
TKJ_TAG_AUTHOR = 'author'
+ TKJ_TAG_DATA = 'data'
+ TKJ_TAG_DESC = 'description'
TKJ_TAG_DIARY = 'diary'
TKJ_TAG_ENTRIES = 'entries'
TKJ_TAG_ENTRY = 'entry'
@@ -361,7 +413,11 @@
TKJ_TAG_TEXT = 'text'
_valid_parents = {
+ TKJ_TAG_ATTACHMENT : [ TKJ_TAG_ATTACHMENTS ],
+ TKJ_TAG_ATTACHMENTS : [ TKJ_TAG_ENTRY ],
TKJ_TAG_AUTHOR : [ TKJ_TAG_DIARY, TKJ_TAG_ENTRY ],
+ TKJ_TAG_DESC : [ TKJ_TAG_ATTACHMENT ],
+ TKJ_TAG_DATA : [ TKJ_TAG_ATTACHMENT ],
TKJ_TAG_DIARY : [ ],
TKJ_TAG_ENTRIES : [ TKJ_TAG_DIARY ],
TKJ_TAG_ENTRY : [ TKJ_TAG_ENTRIES ],
@@ -376,10 +432,11 @@
self.buffer = None
self.entries = entries
self.tag_stack = []
- self.entries.set_author_global(False)
# If we are loading a file, we want there to be no global author
*unless*
# one is actually found in the file (but the default should still
be
# True for new files
+ self.entries.set_author_global(False)
+ self.cur_attachment = None
def _validate_tag(self, name, parent_tag):
valid_parents = self._valid_parents[name]
@@ -425,9 +482,14 @@
self.buffer = ''
elif name == self.TKJ_TAG_TAGS:
self.cur_entry['tags'] = []
+ elif name == self.TKJ_TAG_ATTACHMENT:
+ self.cur_attachment = dict(attrs)
+ self.cur_entry['attachments'] = []
elif name == self.TKJ_TAG_SUBJECT \
or name == self.TKJ_TAG_TAG \
- or name == self.TKJ_TAG_TEXT:
+ or name == self.TKJ_TAG_TEXT \
+ or name == self.TKJ_TAG_DESC \
+ or name == self.TKJ_TAG_DATA:
self.buffer = ''
def characters(self, ch):
@@ -448,7 +510,8 @@
int(self.cur_entry['month']),
int(self.cur_entry['day']),
int(self.cur_entry['id']),
- self.cur_entry.get('tags',
[])))
+ self.cur_entry.get('tags',
[]),
+
self.cur_entry.get('attachments', [])))
self.cur_entry = None
elif name == self.TKJ_TAG_AUTHOR:
if self.cur_entry:
@@ -462,6 +525,19 @@
self.buffer = None
elif name == self.TKJ_TAG_TAG:
self.cur_entry['tags'].append(self.buffer)
+ elif name == self.TKJ_TAG_DESC:
+ self.cur_attachment['description'] = self.buffer
+ self.buffer = None
+ elif name == self.TKJ_TAG_DATA:
+ self.cur_attachment['data'] = base64.decodestring(self.buffer)
+ self.buffer = None
+ elif name == self.TKJ_TAG_ATTACHMENT:
+ attachment =
TKEntryAttachment(self.cur_attachment['description'],
+
self.cur_attachment['content_type'],
+ self.cur_attachment['data'])
+ self.cur_entry['attachments'].append(attachment)
+ self.cur_attachment = None
+
def parse_data(datafile):
"""Parse an XML file, returning a TKEntries object."""
@@ -491,6 +567,7 @@
year, month, day = entry.get_date()
id = entry.get_id()
tags = entry.get_tags()
+ attachments = entry.get_attachments()
fp.write(' <entry year="%s" month="%s" day="%s" id="%s">\n'
% (year, month, day, id))
author = xml.sax.saxutils.escape(entry.get_author())
@@ -507,6 +584,17 @@
fp.write(' <tag>%s</tag>\n'
%
(xml.sax.saxutils.escape(tag.encode('utf8'))))
fp.write(' </tags>\n')
+ if len(attachments):
+ fp.write(' <attachments>\n')
+ for attachment in attachments:
+ fp.write(' <attachment content_type="%s">\n'
+ %
(attachment.get_content_type().encode('utf8')))
+ fp.write(' <description>%s</description>\n'
+ % (attachment.get_description().encode('utf8')))
+ fp.write(' <data>%s</data>\n'
+ % (base64.encodestring(attachment.get_data())))
+ fp.write(' </attachment>\n')
+ fp.write(' </attachments>\n')
fp.write(' <text>%s</text>\n'
%
(xml.sax.saxutils.escape(entry.get_text().encode('utf8'))))
fp.write(' </entry>\n')