3 commits - pykolab/xml tests/unit
Thomas Brüderli
bruederli at kolabsys.com
Thu Mar 26 10:36:29 CET 2015
pykolab/xml/__init__.py | 9 ++
pykolab/xml/event.py | 16 -----
pykolab/xml/note.py | 136 ++++++++++++++++++++++++++++++++++++++++++++
pykolab/xml/utils.py | 18 +++++
tests/unit/test-018-note.py | 95 ++++++++++++++++++++++++++++++
5 files changed, 260 insertions(+), 14 deletions(-)
New commits:
commit 85974d137dd2b37a7d78bffc1d8980cb775f1386
Author: Thomas Bruederli <bruederli at kolabsys.com>
Date: Thu Mar 26 10:35:51 2015 +0100
Add wrapper class for kolabformat.Note (#4908)
diff --git a/pykolab/xml/__init__.py b/pykolab/xml/__init__.py
index 00edf06..20e4763 100644
--- a/pykolab/xml/__init__.py
+++ b/pykolab/xml/__init__.py
@@ -20,6 +20,11 @@ from todo import todo_from_ical
from todo import todo_from_string
from todo import todo_from_message
+from note import Note
+from note import NoteIntegrityError
+from note import note_from_string
+from note import note_from_message
+
from utils import property_label
from utils import property_to_string
from utils import compute_diff
@@ -31,6 +36,7 @@ __all__ = [
"ContactReference",
"Event",
"Todo",
+ "Note",
"RecurrenceRule",
"event_from_ical",
"event_from_string",
@@ -38,6 +44,8 @@ __all__ = [
"todo_from_ical",
"todo_from_string",
"todo_from_message",
+ "note_from_string",
+ "note_from_message",
"property_label",
"property_to_string",
"compute_diff",
@@ -49,6 +57,7 @@ errors = [
"InvalidEventDateError",
"InvalidAttendeeParticipantStatusError",
"TodoIntegrityError",
+ "NoteIntegrityError",
]
__all__.extend(errors)
diff --git a/pykolab/xml/note.py b/pykolab/xml/note.py
new file mode 100644
index 0000000..e46c41c
--- /dev/null
+++ b/pykolab/xml/note.py
@@ -0,0 +1,136 @@
+import pytz
+import datetime
+import kolabformat
+from pykolab.xml import utils as xmlutils
+from pykolab.xml.utils import ustr
+
+def note_from_string(string):
+ _xml = kolabformat.readNote(string, False)
+ return Note(_xml)
+
+def note_from_message(message):
+ note = None
+ if message.is_multipart():
+ for part in message.walk():
+ if part.get_content_type() == "application/vnd.kolab+xml":
+ payload = part.get_payload(decode=True)
+ note = note_from_string(payload)
+
+ # append attachment parts to Note object
+ elif note and part.has_key('Content-ID'):
+ note._attachment_parts.append(part)
+
+ return todo
+
+
+class Note(kolabformat.Note):
+ type = 'note'
+
+ classification_map = {
+ 'PUBLIC': kolabformat.ClassPublic,
+ 'PRIVATE': kolabformat.ClassPrivate,
+ 'CONFIDENTIAL': kolabformat.ClassConfidential,
+ }
+
+ properties_map = {
+ 'uid': 'get_uid',
+ 'summary': 'summary',
+ 'description': 'description',
+ 'created': 'get_created',
+ 'lastmodified-date': 'get_lastmodified',
+ 'classification': 'get_classification',
+ 'categories': 'categories',
+ 'color': 'color',
+ }
+
+ def __init__(self, *args, **kw):
+ self._attachment_parts = []
+ kolabformat.Note.__init__(self, *args, **kw)
+
+ def get_uid(self):
+ uid = self.uid()
+ if not uid == '':
+ return uid
+ else:
+ self.__str__()
+ return kolabformat.getSerializedUID()
+
+ def get_created(self):
+ try:
+ return xmlutils.from_cdatetime(self.created(), True)
+ except ValueError:
+ return datetime.datetime.now()
+
+ def get_lastmodified(self):
+ try:
+ _datetime = self.lastModified()
+ if _datetime == None or not _datetime.isValid():
+ self.__str__()
+ except:
+ return datetime.datetime.now(pytz.utc)
+
+ return xmlutils.from_cdatetime(self.lastModified(), True)
+
+ def set_summary(self, summary):
+ self.setSummary(ustr(summary))
+
+ def set_description(self, description):
+ self.setDescription(ustr(description))
+
+ def get_classification(self, translated=True):
+ _class = self.classification()
+ if translated:
+ return self._translate_value(_class, self.classification_map)
+ return _class
+
+ def set_classification(self, classification):
+ if classification in self.classification_map.keys():
+ self.setClassification(self.classification_map[classification])
+ elif classification in self.classification_map.values():
+ self.setClassification(status)
+ else:
+ raise ValueError, _("Invalid classification %r") % (classification)
+
+ def add_category(self, category):
+ _categories = self.categories()
+ _categories.append(ustr(category))
+ self.setCategories(_categories)
+
+ def _translate_value(self, val, map):
+ name_map = dict([(v, k) for (k, v) in map.iteritems()])
+ return name_map[val] if name_map.has_key(val) else 'UNKNOWN'
+
+ def to_dict(self):
+ if not self.isValid():
+ return None
+
+ data = dict()
+
+ for p, getter in self.properties_map.iteritems():
+ val = None
+ if hasattr(self, getter):
+ val = getattr(self, getter)()
+ if isinstance(val, kolabformat.cDateTime):
+ val = xmlutils.from_cdatetime(val, True)
+ elif isinstance(val, kolabformat.vectori):
+ val = [int(x) for x in val]
+ elif isinstance(val, kolabformat.vectors):
+ val = [str(x) for x in val]
+
+ if val is not None:
+ data[p] = val
+
+ return data
+
+ def __str__(self):
+ xml = kolabformat.writeNote(self)
+ error = kolabformat.error()
+
+ if error == None or not error:
+ return xml
+ else:
+ raise NoteIntegrityError, kolabformat.errorMessage()
+
+class NoteIntegrityError(Exception):
+ def __init__(self, message):
+ Exception.__init__(self, message)
diff --git a/tests/unit/test-018-note.py b/tests/unit/test-018-note.py
new file mode 100644
index 0000000..c4ba764
--- /dev/null
+++ b/tests/unit/test-018-note.py
@@ -0,0 +1,95 @@
+import datetime
+import pytz
+import unittest
+import kolabformat
+
+from pykolab.xml import Note
+from pykolab.xml import NoteIntegrityError
+from pykolab.xml import note_from_string
+
+xml_note = """
+<note xmlns="http://kolab.org" version="3.0">
+ <uid>d407f007-cb52-42cb-8e06-67f6132d718f</uid>
+ <prodid>Roundcube-libkolab-1.1 Libkolabxml-1.1</prodid>
+ <creation-date>2015-03-26T08:12:37Z</creation-date>
+ <last-modification-date>2015-03-26T08:12:37Z</last-modification-date>
+ <categories>One</categories>
+ <categories>Two</categories>
+ <classification>PUBLIC</classification>
+ <summary>Kolab Note</summary>
+ <description><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><meta http-equiv="Content-Type" /></head><body>
+<p>This is a HTML note</p>
+</body></html></description>
+ <color/>
+</note>
+"""
+
+class TestNoteXML(unittest.TestCase):
+ def assertIsInstance(self, _value, _type):
+ if hasattr(unittest.TestCase, 'assertIsInstance'):
+ return unittest.TestCase.assertIsInstance(self, _value, _type)
+ else:
+ if (type(_value)) == _type:
+ return True
+ else:
+ raise AssertionError, "%s != %s" % (type(_value), _type)
+
+ def test_001_minimal(self):
+ note = Note()
+ note.set_summary("test")
+ self.assertEqual(note.summary(), "test")
+ self.assertIsInstance(note.__str__(), str)
+
+ def test_002_full(self):
+ note = Note()
+ note.set_summary("test")
+ note.set_description("Description")
+ note.set_classification("CONFIDENTIAL")
+ note.add_category("Foo")
+ note.add_category("Bar")
+ # print str(note)
+
+ self.assertEqual(len(note.get_uid()), 36)
+ self.assertEqual(note.summary(), "test")
+ self.assertEqual(note.description(), "Description")
+ self.assertEqual(note.get_classification(), "CONFIDENTIAL")
+ self.assertEqual(note.get_classification(False), kolabformat.ClassConfidential)
+ self.assertEqual(len(note.categories()), 2)
+
+ def test_010_load_from_xml(self):
+ note = note_from_string(xml_note)
+ self.assertEqual(note.get_uid(), "d407f007-cb52-42cb-8e06-67f6132d718f")
+ self.assertEqual(note.summary(), "Kolab Note")
+ self.assertIsInstance(note.get_created(), datetime.datetime)
+ self.assertEqual(note.get_created().tzinfo, pytz.utc)
+ self.assertIsInstance(note.get_lastmodified(), datetime.datetime)
+ self.assertEqual(note.get_lastmodified().tzinfo, pytz.utc)
+
+ def test_011_to_xml(self):
+ note = Note()
+ note.setClassification(-1)
+ self.assertRaises(NoteIntegrityError, note.__str__)
+
+ # minimal
+ note = Note()
+ xml = str(note)
+ self.assertTrue('<summary/>' in xml)
+ self.assertTrue('<description/>' in xml)
+
+ def test_020_to_dict(self):
+ data = note_from_string(xml_note).to_dict()
+
+ self.assertIsInstance(data, dict)
+ self.assertTrue(data.has_key('uid'))
+ self.assertIsInstance(data.get('created', None), datetime.datetime)
+ self.assertIsInstance(data.get('lastmodified-date', None), datetime.datetime)
+ self.assertEqual(data.get('summary', None), "Kolab Note")
+ self.assertEqual(data.get('classification', None), 'PUBLIC')
+ self.assertIsInstance(data.get('categories', None), list)
+ self.assertEqual(len(data.get('categories', None)), 2)
+ self.assertTrue('<p>This is a HTML note</p>' in data.get('description', None))
+
+
+if __name__ == '__main__':
+ unittest.main()
\ No newline at end of file
commit 035978ff20b1336ec2db06e3f73a4449ea9ddb72
Author: Thomas Bruederli <bruederli at kolabsys.com>
Date: Thu Mar 26 10:22:43 2015 +0100
Move ustr() to xml utilities module
diff --git a/pykolab/xml/utils.py b/pykolab/xml/utils.py
index 261e33c..9d80f9c 100644
--- a/pykolab/xml/utils.py
+++ b/pykolab/xml/utils.py
@@ -127,6 +127,24 @@ def dates_equal(a, b):
return type(a) == type(b) and a.strftime(date_format) == b.strftime(date_format)
+def ustr(s):
+ """
+ Force the given (unicode) string into UTF-8 encoding
+ """
+ if not isinstance(s, unicode):
+ for cs in ['utf-8','latin-1']:
+ try:
+ s = unicode(s, cs)
+ break
+ except:
+ pass
+
+ if isinstance(s, unicode):
+ return s.encode('utf-8')
+
+ return s
+
+
property_labels = {
"name": N_("Name"),
"summary": N_("Summary"),
commit 7566d1439506543bdf885a3350e4363dde109fdd
Author: Thomas Bruederli <bruederli at kolabsys.com>
Date: Thu Mar 26 10:21:50 2015 +0100
Fix varname and avoid throwing an execption on every call
diff --git a/pykolab/xml/event.py b/pykolab/xml/event.py
index 5080e43..e2e5440 100644
--- a/pykolab/xml/event.py
+++ b/pykolab/xml/event.py
@@ -12,6 +12,7 @@ from pykolab import constants
from pykolab import utils
from pykolab.xml import utils as xmlutils
from pykolab.xml import participant_status_label
+from pykolab.xml.utils import ustr
from pykolab.translate import _
from os import path
@@ -21,19 +22,6 @@ from recurrence_rule import RecurrenceRule
log = pykolab.getLogger('pykolab.xml_event')
-def ustr(s):
- if not isinstance(s, unicode):
- for cs in ['utf-8','latin-1']:
- try:
- s = unicode(s, cs)
- break
- except:
- pass
-
- if isinstance(s, unicode):
- return s.encode('utf-8')
-
- return s
def event_from_ical(ical, string=None):
return Event(from_ical=ical, from_string=string)
@@ -680,7 +668,7 @@ class Event(object):
def get_lastmodified(self):
try:
_datetime = self.event.lastModified()
- if retval == None or retval == "":
+ if _datetime == None or not _datetime.isValid():
self.__str__()
except:
self.__str__()
More information about the commits
mailing list